home *** CD-ROM | disk | FTP | other *** search
/ Aminet 15 / Aminet 15 - Nov 1996.iso / Aminet / dev / lang / FPL_v147.lha / fpl / src / numexpr.c < prev    next >
C/C++ Source or Header  |  1996-04-09  |  89KB  |  2,684 lines

  1. /******************************************************************************
  2.  *                        FREXX PROGRAMMING LANGUAGE                          *
  3.  ******************************************************************************
  4.  
  5.  numexpr.c
  6.  
  7.  Supports *FULL* C language expression operator priority and much more...!
  8.  
  9.  *****************************************************************************/
  10.  
  11. /************************************************************************
  12.  *                                                                      *
  13.  * fpl.library - A shared library interpreting script langauge.         *
  14.  * Copyright (C) 1992-1994 FrexxWare                                    *
  15.  * Author: Daniel Stenberg                                              *
  16.  *                                                                      *
  17.  * This program is free software; you may redistribute for non          *
  18.  * commercial purposes only. Commercial programs must have a written    *
  19.  * permission from the author to use FPL. FPL is *NOT* public domain!   *
  20.  * Any provided source code is only for reference and for assurance     *
  21.  * that users should be able to compile FPL on any operating system     *
  22.  * he/she wants to use it in!                                           *
  23.  *                                                                      *
  24.  * You may not change, resource, patch files or in any way reverse      *
  25.  * engineer anything in the FPL package.                                *
  26.  *                                                                      *
  27.  * This program is distributed in the hope that it will be useful,      *
  28.  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
  29.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                 *
  30.  *                                                                      *
  31.  * Daniel Stenberg                                                      *
  32.  * Ankdammsgatan 36, 4tr                                                *
  33.  * S-171 43 Solna                                                       *
  34.  * Sweden                                                               *
  35.  *                                                                      *
  36.  * FidoNet 2:201/328    email:dast@sth.frontec.se                       *
  37.  *                                                                      *
  38.  ************************************************************************/
  39.  
  40. #ifdef AMIGA
  41. #include <exec/types.h>
  42. #include <proto/exec.h>
  43. #elif defined(UNIX)
  44. #include <sys/types.h>
  45. #endif
  46.  
  47. #include "script.h"
  48. #include <stdio.h>
  49. #include <stddef.h>
  50. #include <limits.h>
  51.  
  52. #include "debug.h"
  53.  
  54. static ReturnCode INLINE GetArrayInfo(struct Data *, long *, long *, long, uchar *);
  55. static ReturnCode INLINE Convert(struct Expr *, struct Data *);
  56. static ReturnCode INLINE PrototypeInside(struct Data *,
  57.                      struct Expr *val,
  58.                      long,
  59.                      struct Identifier *);
  60. static ReturnCode INLINE inside(struct Data *, struct fplArgument *,
  61.                                 struct Identifier *);
  62.  
  63. #ifdef STRING_STACK
  64. static ReturnCode INLINE StringToStack(struct Data *,
  65.                                        struct fplStr **);
  66. static ReturnCode INLINE StringFromStack(struct Data *,
  67.                                          struct fplStr **);
  68. #endif
  69.  
  70. /***********************************************************************
  71.  *
  72.  * int Expression(struct Expr *, struct Data *, uchar, struct Local *)
  73.  *
  74.  * Returns a nonzero value if any error occured.
  75.  * The result of the Expression is returned in the Expr structure which you
  76.  * give the pointer to in the first argument.
  77.  *
  78.  *****************/
  79.  
  80. ReturnCode REGARGS
  81. Expression(struct Expr *val, /* return value struct pointer */
  82.            struct Data *scr, /* everything */
  83.            long control,    /* ESPECIALLLY DEFINED */
  84.            struct Identifier *ident) /* pointer to the pointer holding
  85.                                         the local variable names linked
  86.                                         list */
  87. {
  88.   struct Expr *expr, *basexpr;
  89.   ReturnCode ret;
  90.   struct Identifier *pident; /* general purpose struct identifier pointer */
  91.   struct Unary *un; /* general purpose struct Unary pointers */
  92.   long *dims=NULL; /* dimension pointer for variable arrays! */
  93.   long pos;       /* general purpose integer */
  94.   uchar *text;     /* general purpose char pointer */
  95.   uchar hit;
  96.   uchar *array;
  97.   long num;
  98.   long *nump;     /* for general purpose long pointers */
  99.   struct fplMsg *msg;
  100.   struct fplStr *string;
  101. #if defined(AMIGA) && defined(SHARED)
  102.   if(ret=CheckStack(scr, scr->stack_limit, scr->stack_margin)) {
  103.     if(ret==1)
  104.       return(FPLERR_OUT_OF_MEMORY);
  105.     else
  106.       return(FPLERR_OUT_OF_STACK);
  107.   }
  108. #endif
  109.  
  110.   GETMEM(expr, sizeof(struct Expr));
  111.   memset(expr, 0, sizeof(struct Expr));
  112.   basexpr=expr;
  113.  
  114.   do {
  115.     if(ret=Eat(scr)) {       /* getaway blanks and comments */
  116.       if(control&CON_END && ret==FPLERR_UNEXPECTED_END) {
  117.         /* If there can be an unexpected ending, break out of the loop
  118.            with a nice return code! */
  119.         break;
  120.       }
  121.     } else if(expr->flags&FPL_STRING && !(control&CON_GROUNDLVL))
  122.       /* get outta string calcs if not on ground level! */
  123.       break;
  124.  
  125.     if(!(expr->flags&FPL_OPERAND)) {  /* operand coming up */
  126.  
  127.       if(control&CON_IDENT || isident(*scr->text)) {
  128.         /*
  129.          * It's a valid identifier character.
  130.          */
  131.         uchar *point;
  132.         num=0; /* Dimension counter when taking care of array variables */
  133.  
  134.         if(control&CON_IDENT) {
  135.           if(!ident)
  136.             ret=FPLERR_IDENTIFIER_NOT_FOUND;
  137.           control&=~CON_IDENT; /* switch off that bit to get away from any
  138.                                   trouble such as double using this! */
  139.         } else {
  140.           CALL(Getword(scr));
  141.           ret=GetIdentifier(scr, scr->buf, &ident);
  142.         }
  143.  
  144.         point=scr->text;
  145.         Eat(scr); /* getaway blanks */
  146.  
  147.         /*
  148.          * `ret' can only be FPL_OK or FPLERR_IDENTIFIER_NOT_FOUND at this
  149.          * position.
  150.          */
  151.  
  152.         if(control&CON_DECLARE && *scr->text==CHAR_OPEN_PAREN) {
  153.       CALL(PrototypeInside(scr, val, control, ident));
  154.       expr->flags|=FPL_OPERAND|FPL_ACTION;
  155.  
  156.         } else if(control&CON_DECLARE ||
  157.                   (ident && ident->flags&FPL_VARIABLE)) {
  158.           /* The ident check above really must be there, otherwise we might
  159.              read it when it is a NULL pointer" */
  160.  
  161.           /* it's a variable */
  162.           pident=ident;
  163.           if(ret &&                     /* we didn't find it... */
  164.              !(control&CON_DECLARE))    /* and we're not declaring! */
  165.             /*
  166.              * We didn't find the requested identifier and we're *NOT*
  167.              * declaring. This means error!
  168.              */
  169.             return(ret);
  170.           else if(!ret) {
  171.         if(ident->flags&FPL_REFERENCE)
  172.           return FPLERR_ILLEGAL_VARIABLE; /* this is a reference _only_! */
  173.  
  174.             /* The symbol was found */
  175.         if(control&CON_LEVELOK) /* level _is_ OK! */
  176.           ;
  177.             else if(control&CON_DECLARE &&
  178.            (ident->level>=scr->varlevel || scr->varlevel==1)) {
  179.               /*
  180.                * If the name already declared in this (or higher) level
  181.                * and declaration is wanted.
  182.                */
  183.               if((ident->flags&FPL_STATIC_VARIABLE &&
  184.                   control&CON_DECLSTATIC &&
  185.                   ident->level==scr->varlevel) ||
  186.                  /*
  187.                   * If this is a `static' variable and the variable already
  188.                   * exists on this very level in this very function as static,
  189.                   * then skip this. It's perfectly OK to jump to the ending
  190.                   * semicolon since this has been parsed before!
  191.                   */
  192.  
  193.                  (ident->flags&FPL_EXPORT_SYMBOL && control&CON_DECLEXP)) {
  194.  
  195.                 /*
  196.                  * If this is an `export' symbol and it already exists as an
  197.                  * `export' symbol! Then just ignore this!
  198.                  */
  199.  
  200.                 /*
  201.                  * The current implementation unfortunately uses the statement
  202.                  * below to pass this declaration. That means comma-
  203.                  * separated exported symbols will be passed if only the first
  204.                  * is alredy declared... This will although work in all those
  205.                  * cases it is the SAME code that is executed twice!
  206.                  */
  207.  
  208.  
  209.                 if(GetEnd(scr, CHAR_SEMICOLON, 255, FALSE))
  210.                   return FPLERR_MISSING_SEMICOLON;
  211.                 scr->text--; /* get back on the semicolon! */
  212.                 break;
  213.               } else {
  214.                 CALL(Warn(scr, FPLERR_IDENTIFIER_USED));
  215.                 /* run it over! */
  216.                 DelIdentifier(scr, ident->name, NULL);
  217.               }
  218.             } else if(!(control&CON_DECLARE) &&
  219.                       (ident->level && /* not global */
  220.                        ident->level<(scr->varlevel-scr->level)))
  221.               /*
  222.                * From the wrong program level and we're not declaring.
  223.                */
  224.               return(FPLERR_IDENTIFIER_NOT_FOUND);
  225.             else if(ident->flags&FPL_STATIC_VARIABLE &&
  226.                     ((ident->func && (ident->func==scr->func)) ||
  227.                      ident->level>scr->varlevel)
  228.                     )
  229.               /*
  230.                * A static variable declared either in the wrong function or
  231.                * in a higher level!
  232.                */
  233.               return(FPLERR_IDENTIFIER_NOT_FOUND);
  234.           }
  235.  
  236.           text = NULL; /* no name information yet! */
  237.  
  238.       control &= ~CON_LEVELOK; /* forget about the level OK stuff!! */
  239.  
  240.           if(*scr->text==CHAR_OPEN_BRACKET) {
  241.             /*
  242.              * It's an array. Get the result of the expression within the
  243.              * square brackets.
  244.              */
  245.  
  246.             if(!dims) {
  247.               GETMEM(dims, MAX_DIMS*sizeof(long));
  248.             }
  249.             if(!(control&CON_DECLARE) && pident->data.variable.size)
  250.               num=pident->data.variable.num;
  251.             if(control&CON_DECLARE || num) {
  252.               /*
  253.                * Get the name now, cause the GetArrayInfo() call may
  254.                * destroy the 'scr->buf' buffer!
  255.                */
  256.               STRDUP(text, scr->buf);
  257.  
  258.               GETMEM(nump, sizeof(long));
  259.               *nump = num;
  260.               CALL(GetArrayInfo(scr, dims, nump, control, text));
  261.               num = *nump;
  262.               FREE(nump);
  263.               if(!(control&CON_DECLARE)) {
  264.                 /*
  265.                  * Free the name now, cause we don't declare anything
  266.                  * and this isn't needed any more!
  267.                  */
  268.                 FREE(text);
  269.                 text = NULL;
  270.               }
  271.               if(!(control&CON_DECLARE)) {
  272.                 if(num > pident->data.variable.num) {
  273.                   /*
  274.                    * If not declaring and overfilled quota: fail!
  275.                    *
  276.                    *
  277.                    * Copy the variable name to the buffer to make the
  278.                    * error message look good!
  279.                    */
  280.                   strcpy(scr->buf, pident->name);
  281.                   return FPLERR_ILLEGAL_ARRAY;
  282.                   
  283.                 } else {
  284.                   for(pos=0; pos<num; pos++)
  285.                     if(pident->data.variable.dims[pos]<=dims[pos]) {
  286.                       /*
  287.                        * Copy the variable name to the buffer to make the
  288.                        * error message look good!
  289.                        */
  290.                       strcpy(scr->buf, pident->name);
  291.                       return FPLERR_ILLEGAL_ARRAY;
  292.                     }
  293.                 }
  294.               }
  295.               point=scr->text; /* move point to current location  */
  296.               Eat(scr); /* pass all traling whitespaces */
  297.             }
  298.           }
  299.           if(control&CON_DECLARE) {
  300.             expr->flags|=FPL_ACTION;
  301.             GETMEM(pident, sizeof(struct Identifier));
  302.  
  303.             pident->level=
  304.               (control&(CON_DECLEXP|CON_DECLGLOB))?0:scr->varlevel;
  305.             pident->flags=
  306.               (control&CON_DECLINT?FPL_INT_VARIABLE:FPL_STRING_VARIABLE)|
  307.                 (control&CON_DECLEXP?FPL_EXPORT_SYMBOL:0)|
  308.  
  309.                   (control&CON_DECLGLOB?FPL_GLOBAL_SYMBOL:
  310.                     (control&CON_DECLSTATIC?FPL_STATIC_VARIABLE:0))|
  311.  
  312.                     (control&CON_DECL8?FPL_CHAR_VARIABLE:
  313.                      (control&CON_DECL16?FPL_SHORT_VARIABLE:0))|
  314.  
  315.                        (control&CON_DECLCONST?FPL_READONLY:0);
  316.  
  317.             pident->file=scr->prog->name; /* file */
  318.  
  319.             pident->func=scr->func; /* declared in this function */
  320.  
  321.             /* Get variable name */
  322.             if(text)
  323.               /*
  324.                * The name has already been allocated above!
  325.                */
  326.               pident->name = text;
  327.             else {
  328.               /*
  329.                * Get the name!
  330.                */
  331.               STRDUP(pident->name, scr->buf); /* no real strdup */
  332.             }
  333.             if(num) {
  334.               /*
  335.                * Array variable declaration! It is a bit different from
  336.                * common variable declaration so I decided to put the code
  337.                * for it right here:
  338.                */
  339.               long size=dims[0]; /* array size */
  340.  
  341.               for(pos=1; pos<num; pos++)
  342.                 size*=dims[pos];
  343.  
  344.               /* Now `size' is the total number of members in the array we're
  345.                  about to declare */
  346.  
  347.               /* Get memory for the dimension array */
  348.               GETMEM(pident->data.variable.dims, num * sizeof(long));
  349.  
  350.               /* Copy the dim info to the newly allocated area */
  351.               memcpy((void *)pident->data.variable.dims, dims, num*sizeof(long));
  352.  
  353.               /* Get memory for the array  */
  354.               GETMEM(pident->data.variable.var.val32, size * sizeof(long));
  355.  
  356.               /* Set all string lengths to NULL and integers to zero: */
  357.               memset(pident->data.variable.var.val32, 0, size * sizeof(void *));
  358.  
  359.               pident->data.variable.size=size; /* total number of array members */
  360.               pident->data.variable.num=num;   /* number of dimensions */
  361.  
  362.               /* reset the dims array! */
  363.               memset((void *)dims, 0, sizeof(long) * num);
  364.  
  365.               /* reset num: */
  366.               num=1;
  367.  
  368.             } else {
  369. #ifdef DEBUG
  370.               CheckMem(scr, pident);
  371. #endif
  372.  
  373.               GETMEM(pident->data.variable.var.val32, sizeof(long));
  374.               *pident->data.variable.var.val32=0;
  375.               pident->data.variable.num=0;
  376.               pident->data.variable.size=1;
  377.             }
  378.             /*
  379.              * We add the symbol to the local data in all cases except when
  380.              * the symbol is global or static.
  381.              */
  382.             CALL(AddVar(scr, pident,
  383.                         control&(CON_DECLGLOB|CON_DECLSTATIC)?
  384.                         &scr->globals:&scr->locals));
  385.           }
  386.  
  387.           /*
  388.            * Now when all declarations is done, all assigns are left:
  389.            */
  390.  
  391.           expr->flags|=FPL_OPERAND;
  392.           if (pident->flags&FPL_STRING_VARIABLE) { /* string variable */
  393.             if(*scr->text==CHAR_OPEN_BRACKET) { /* just one character */
  394.               /*
  395.                * Get the result of the expression.
  396.                */
  397.               uchar *value;
  398.               if(control&CON_STRING) {
  399.                 /* NO integers allowed! */
  400.                 return FPLERR_UNEXPECTED_INT_STATEMENT;
  401.               }
  402.               CALL(Expression(val, (scr->text++, scr),
  403.                               CON_GROUNDLVL|CON_NUM, NULL));
  404.               if(val->val.val<0) {
  405.                 strcpy(scr->buf, pident->name);
  406.                 return FPLERR_STRING_INDEX; /* we don't know what was meant! */
  407.               }
  408.  
  409.               if(*scr->text!=CHAR_CLOSE_BRACKET) {
  410.                 CALL(Warn(scr, FPLERR_MISSING_BRACKET));
  411.                 /* we can continue anyway! */
  412.               } else
  413.                 scr->text++;
  414.  
  415.               CALL(Eat(scr)); /* eat white space */
  416.  
  417.               if(pident->data.variable.num) {
  418.                 /* pick out the proper array member */
  419.                 pos=ArrayNum(num, pident->data.variable.num,
  420.                              dims, pident->data.variable.dims);
  421.                 if(pos<0) {
  422.                   strcpy(scr->buf, pident->name);
  423.                   return FPLERR_ILLEGAL_ARRAY; /* we don't know what was meant! */
  424.                 }
  425.               } else
  426.                 pos=0;
  427.  
  428.               if(!pident->data.variable.var.str[pos] ||
  429.                  !pident->data.variable.var.str[pos]->len)
  430.                 /* no-length-string */
  431.                 return FPLERR_STRING_INDEX;
  432.               
  433.               if(val->val.val >= pident->data.variable.var.str[pos]->len) {
  434.                 /* force to zero! */
  435.                 val->val.val=0;
  436.               }
  437.               /*
  438.                * (I) Here we should be able to operate the character read
  439.                * from the string. ++ and -- should work to enable advanced
  440.                * string modification handling without the
  441.                * overhead of getting the string, changing it and then re-
  442.                * assign it back. This *MUST* be implemented soon cause
  443.                * it's a real killer!
  444.                */
  445.  
  446.               value=(uchar *)&pident->data.variable.var.str[pos]->string[val->val.val];
  447.  
  448.               if(ASSIGN_OPERATOR) {
  449.                 uchar was=*scr->text;
  450.                 long valint=*value;
  451.                 if(pident->flags&FPL_READONLY)
  452.                   return FPLERR_READONLY_VIOLATE;                  
  453.                 expr->flags|=FPL_ACTION;
  454.                 if(*scr->text==CHAR_ASSIGN)
  455.                   scr->text++;
  456.                 else if(scr->text[2]==CHAR_ASSIGN)
  457.                   scr->text+=3;
  458.                 else
  459.                   scr->text+=2;
  460.                 /* single assign */
  461.                 CALL(Expression(val, scr, CON_NORMAL|CON_NUM, NULL));
  462.                 CALL(CmpAssign(scr, val->val.val, &valint, FPL_CHAR_VARIABLE,
  463.                                was));
  464.                 *value=valint;
  465.               }
  466.  
  467.               expr->val.val=*value; /* only one byte */
  468.               CALL(NewMember(scr, &expr));
  469.             } else if(control&CON_NUM) {
  470.               /* NO strings allowed! */
  471.               return FPLERR_UNEXPECTED_STRING_STATEMENT;
  472.               /* be able to continue here, we must pass everything that has to
  473.                  to with the strings in this expression */
  474.             } else if (*scr->text==CHAR_ASSIGN || (*scr->text==CHAR_PLUS &&
  475.                         scr->text[1]==CHAR_ASSIGN)) {
  476.               uchar array=FALSE;
  477.               uchar multi=FALSE;
  478.               struct fplStr **string; /* current string */
  479.               uchar app=(*scr->text==CHAR_PLUS);
  480.  
  481.               if(pident->flags&FPL_READONLY && !(control&CON_DECLARE))
  482.                 return FPLERR_READONLY_VIOLATE;
  483.  
  484.               scr->text+=1+app;
  485.               expr->flags|=FPL_ACTION;
  486.               if(pident->data.variable.num) { /* if array member assign */
  487.                 Eat(scr);
  488.                 if(*scr->text==CHAR_OPEN_BRACE) {
  489.                   /* array assign */
  490.                   multi=TRUE;
  491.                   scr->text++;
  492.                   CALL(Eat(scr));
  493.                 }
  494.                 array=TRUE;
  495.               }
  496.  
  497.               if(!multi) {
  498.                 /* single (array) variable assign */
  499.                 if(array) {
  500.                   pos=ArrayNum(num, pident->data.variable.num,
  501.                                dims, pident->data.variable.dims);
  502.                   if(pos<0) {
  503.                     CALL(Warn(scr, FPLERR_ILLEGAL_ARRAY));
  504.                     pos=0; /* we don't know what was meant! */
  505.                   }
  506.                 } else
  507.                   pos=0;
  508.         CALL(Expression(val, scr, CON_STRING, NULL));
  509.         CALL(StringExpr(val, scr)); /* get more strings? */
  510.                 string=&pident->data.variable.var.str[pos];
  511.                 if(!app && val->flags&FPL_NOFREE) {
  512.                   /*
  513.                    * Only do this this is not an append action _and_
  514.                    * we can't free this string (== someone else is
  515.                    * taking care of this string!)
  516.                    */
  517.                   if(*string) {
  518.                     FREE_KIND(*string); /* free old string */
  519.                   }
  520.                   if(val->val.str) {
  521.                     /* duplicate string */
  522.                     STRFPLDUP((*string), val->val.str);
  523.                   }
  524.                   else
  525.                     *string=NULL;
  526.                 } else {
  527.                   CALL(StrAssign(val->val.str, scr, string, app));
  528.                 }
  529.                 if(*string && MALLOC_STATIC == TypeMem(pident) )
  530.                   SwapMem(scr, *string, MALLOC_STATIC);
  531.                 if(app && !(val->flags&FPL_NOFREE) && val->val.str)
  532.                   /* Only do this if appending! */
  533.                   FREE(val->val.str);
  534.               } else {
  535.                 /* multi [compound] assign! */
  536.  
  537.                 /*
  538.                  * Count the preceding open braces to get proper level
  539.                  * to assign in.
  540.                  */
  541.                 while(*scr->text==CHAR_OPEN_BRACE) {
  542.                   num++; /* next dimension */
  543.                   scr->text++; /* pass it! */
  544.                   CALL(Eat(scr));
  545.                 }
  546.  
  547.                 do {
  548.                   do {
  549.                     hit=TRUE;
  550.  
  551.                     /* parse the controlling braces and commas */
  552.                     switch(*scr->text) {
  553.                     case CHAR_CLOSE_BRACE:
  554.  
  555.                       num--; /* back one dimension */
  556.                       if(num>=0 && num<pident->data.variable.num)
  557.                         dims[num]=0;
  558.                       else {
  559.                         CALL(Warn(scr,FPLERR_ILLEGAL_ARRAY));
  560.                         num=0; /* force counter to zero! */
  561.                       }
  562.                       scr->text++;
  563.                       break;
  564.                     case CHAR_COMMA:
  565.                       /*
  566.                        * Increase the last dimension member for next loop:
  567.                        */
  568.  
  569.                       if(num>0 && num<=pident->data.variable.num)
  570.                         dims[num-1]++;
  571.                       else {
  572.                         CALL(Warn(scr, FPLERR_ILLEGAL_ARRAY));
  573.                         /* force counter back to top position! */
  574.                         num=pident->data.variable.num;
  575.                       } scr->text++;
  576.                       break;
  577.                     case CHAR_OPEN_BRACE:
  578.                       num++; /* next dimension */
  579.                       scr->text++;
  580.                       break;
  581.                     default:
  582.                       hit=FALSE;
  583.                       break;
  584.                     }
  585.                     if(hit && !ret) {
  586.                       CALL(Eat(scr));
  587.                     } else
  588.                       break;
  589.                   } while(1);
  590.  
  591.  
  592.                   if(!num)
  593.                     break;
  594.  
  595.                   pos=ArrayNum(num, pident->data.variable.num,
  596.                                dims, pident->data.variable.dims);
  597.                   if(pos<0) {
  598.                     CALL(Warn(scr, FPLERR_ILLEGAL_ARRAY));
  599.                     pos=0; /* force back to sane number */
  600.                   }
  601.  
  602.                   /* assign! */
  603.  
  604.                   string=&pident->data.variable.var.str[pos];
  605.  
  606.           CALL(Expression(val, scr, CON_STRING, NULL));
  607.           CALL(StringExpr(val, scr)); /* get more strings? */
  608.  
  609.                   if(!app && val->flags&FPL_NOFREE) {
  610.                     /*
  611.                      * Only do this this is not an append action _and_
  612.                      * we can't free this string (== someone else is
  613.                      * taking care of this string!)
  614.                      */
  615.                     if(*string) {
  616.                       FREE_KIND(*string); /* free old string */
  617.                     }
  618.                     if(val->val.str) {
  619.                       STRFPLDUP((*string), val->val.str); /* duplicate string */
  620.                     }
  621.                     else
  622.                       *string = NULL;
  623.                   } else {
  624.                     CALL(StrAssign(val->val.str, scr, string, app));
  625.                   }
  626.                   if(*string && MALLOC_STATIC == TypeMem(pident))
  627.                     SwapMem(scr, *string, MALLOC_STATIC);
  628.  
  629.                   if(app && !(val->flags&FPL_NOFREE) && val->val.str) {
  630.                     /* only if we're appending! */
  631.                     FREE(val->val.str);
  632.                   }
  633.  
  634. #ifdef STRING_STACK
  635.                   if(app)
  636.                     /* the string couldn't be freed, but we let them know that
  637.                        we don't use it anymore! */
  638.                     val->val.str->flags=FPLSTR_UNUSED;
  639. #endif
  640.                   /* while  */
  641.                 } while(1);
  642.               }
  643.               expr->val.str=*string;
  644.               expr->flags|=FPL_STRING|FPL_NOFREE;
  645.             } else {
  646.               if(control&CON_DECLARE)
  647.                 expr->val.val=0;
  648.               else if(pident->data.variable.num) {
  649.                 pos=ArrayNum(num, pident->data.variable.num,
  650.                              dims, pident->data.variable.dims);
  651.                 if(pos<0) {
  652.                   CALL(Warn(scr, FPLERR_ILLEGAL_ARRAY));
  653.                   pos=0; /* force back to sane number */
  654.                 }
  655.                 expr->val.str=pident->data.variable.var.str[pos];
  656.               } else
  657.                 expr->val.str=pident->data.variable.var.str[0];
  658.               expr->flags|=FPL_STRING|FPL_NOFREE;
  659.           CALL(StringExpr(expr, scr));
  660.             }
  661.           } else {
  662.             /*
  663.              * Integer variable...
  664.              */
  665.             if(control&CON_STRING) {
  666.               /* NO integers allowed! */
  667.               return FPLERR_UNEXPECTED_INT_STATEMENT;
  668.             }
  669. #if 0
  670.             if(pident->flags&FPL_READONLY && !(control&CON_DECLARE)) {
  671.               if(!pident->data.variable.num)
  672.                 expr->val.val=pident->data.variable.var.val32[0];
  673.               else {
  674.                 pos=ArrayNum(num, pident->data.variable.num,
  675.                              dims, pident->data.variable.dims);
  676.                 if(pos<0) {
  677.                   CALL(Warn(scr, FPLERR_ILLEGAL_ARRAY));
  678.                   pos=0; /* force back to sane number */
  679.                 }
  680.  
  681.                 expr->val.val=pident->data.variable.var.val32[pos];
  682.               }
  683.             } else
  684. #endif
  685.               if(!expr->operator && !expr->unary &&
  686.                       ASSIGN_OPERATOR) {
  687.  
  688.               /* integer assign */
  689.  
  690.               uchar array=FALSE;    /* is it an array variable */
  691.               uchar multi=FALSE;    /* mutiple variable */
  692.               uchar was=*scr->text;
  693.  
  694.               if(pident->flags&FPL_READONLY && !(control&CON_DECLARE))
  695.                 return FPLERR_READONLY_VIOLATE;
  696.  
  697.               expr->flags|=FPL_ACTION;
  698.               if(*scr->text==CHAR_ASSIGN)
  699.                 scr->text++;
  700.               else if(scr->text[2]==CHAR_ASSIGN)
  701.                 scr->text+=3;
  702.               else
  703.                 scr->text+=2;
  704.               if(pident->data.variable.num) { /* if array member assign */
  705.                 Eat(scr);
  706.                 if(*scr->text==CHAR_OPEN_BRACE) {
  707.  
  708.                   /* array assign */
  709.                   multi=TRUE;
  710.                   scr->text++;
  711.                   CALL(Eat(scr));
  712.                 }
  713.                 array=TRUE;
  714.               }
  715.  
  716.               if(!multi) {
  717.                 if(!array)
  718.                   pos=0;
  719.                 else {
  720.                   /* single (array) variable assign */
  721.                   pos=ArrayNum(num, pident->data.variable.num,
  722.                                dims, pident->data.variable.dims);
  723.                   if(pos<0) {
  724.                     CALL(Warn(scr, FPLERR_ILLEGAL_ARRAY));
  725.                     pos=0; /* force back to a decent number */
  726.                   }
  727.                 }
  728.  
  729.                 CALL(Expression(val, scr, CON_NORMAL|CON_NUM, NULL));
  730.  
  731.                 CALL(CmpAssign(scr, val->val.val,
  732.                                &pident->data.variable.var.val32[pos],
  733.                                pident->flags, was));
  734.                 expr->val.val=pident->data.variable.var.val32[pos];
  735.               } else {
  736.                 /* multi [compound] assign */
  737.  
  738.                 /*
  739.                  * Count the preceding open braces to get proper level
  740.                  * to assign in.
  741.                  */
  742.                 while(*scr->text==CHAR_OPEN_BRACE) {
  743.                   num++; /* next dimension */
  744.                   scr->text++; /* pass it! */
  745.                   CALL(Eat(scr));
  746.                 }
  747.  
  748.                 do {
  749.                   while(1) {
  750.                     uchar hit=TRUE;
  751.  
  752.                     /* parse the controlling braces and commas */
  753.                     switch(*scr->text) {
  754.                     case CHAR_CLOSE_BRACE:
  755.  
  756.                       num--; /* back one dimension */
  757.                       if(num>=0 && num<pident->data.variable.num)
  758.                         dims[num]=0;
  759.                       else {
  760.                         CALL(Warn(scr, FPLERR_ILLEGAL_ARRAY));
  761.                         num=0;
  762.                       }
  763.                       scr->text++;
  764.                       break;
  765.                     case CHAR_COMMA:
  766.                       /*
  767.                        * Increase the last dimension member for next loop:
  768.                        */
  769.                       if(num>0 && num<=pident->data.variable.num)
  770.                         dims[num-1]++;
  771.                       else {
  772.                         CALL(Warn(scr, FPLERR_ILLEGAL_ARRAY));
  773.                         num=pident->data.variable.num;
  774.                       }
  775.                       scr->text++;
  776.                       break;
  777.                     case CHAR_OPEN_BRACE:
  778.                       num++; /* next dimension */
  779.                       scr->text++;
  780.                       break;
  781.                     default:
  782.                       hit=FALSE;
  783.                       break;
  784.                     }
  785.                     if(hit && !ret) {
  786.                       CALL(Eat(scr));
  787.                     } else
  788.                       break;
  789.                   }
  790.  
  791.                   if(!num)
  792.                     break;
  793.  
  794.                   pos=ArrayNum(num, pident->data.variable.num,
  795.                                dims, pident->data.variable.dims);
  796.                   if(pos<0) {
  797.                     CALL(Warn(scr, FPLERR_ILLEGAL_ARRAY));
  798.                     pos=0;
  799.                   }
  800.  
  801.                   /* assign! */
  802.                   CALL(Expression(val, scr, CON_NORMAL|CON_NUM, NULL));
  803.                   CALL(CmpAssign(scr, val->val.val, &pident->data.variable.var.val32[pos],
  804.                                  pident->flags, was));
  805.                   expr->val.val=pident->data.variable.var.val32[pos];
  806.  
  807.                   /* while  */
  808.                 } while(1);
  809.               }
  810.               expr->flags|=FPL_NOFREE; /* the memory pointed to by the expr->val.val
  811.                                           is strings of proper variables. Do
  812.                                           not free them now! */
  813.             } else {
  814.               /*
  815.                * No assignment, primary operator or none at all!
  816.                */
  817.               long *value;
  818.               if(control&CON_DECLARE)
  819.                 expr->val.val=0;
  820.               else {
  821.                 if(pident->data.variable.num) {
  822.                   pos=ArrayNum(num, pident->data.variable.num,
  823.                                dims, pident->data.variable.dims);
  824.                   if(pos<0) {
  825.                     CALL(Warn(scr, FPLERR_ILLEGAL_ARRAY));
  826.                     pos=0;
  827.                   }
  828.                 } else
  829.                   pos=0;
  830.                 value=&pident->data.variable.var.val32[pos];
  831.  
  832.                 if(*point==CHAR_PLUS && point[1]==CHAR_PLUS) {
  833.                   /*post increment*/
  834.                   if(pident->flags&FPL_READONLY)
  835.                     return FPLERR_READONLY_VIOLATE;                  
  836.                   expr->flags|=FPL_ACTION;
  837.                   expr->val.val=(*value)++;
  838.                   scr->text+=2;
  839.                 } else if(*point==CHAR_MINUS && point[1]==CHAR_MINUS) {
  840.                   /* post decrement */
  841.                   if(pident->flags&FPL_READONLY)
  842.                     return FPLERR_READONLY_VIOLATE;                  
  843.  
  844.                   expr->flags|=FPL_ACTION;
  845.                   expr->val.val=(*value)--;
  846.                   scr->text+=2;
  847.                 } else {
  848.                   /* plain variable or pre operation */
  849.                   if(un=expr->unary) {
  850.                     if(un->unary!=OP_PREINC && un->unary!=OP_PREDEC) {
  851.                       expr->val.val=*value;
  852.                     } else {
  853.                       if(pident->flags&FPL_READONLY)
  854.                         return FPLERR_READONLY_VIOLATE;
  855.                       if(un->unary==OP_PREINC)
  856.                         expr->val.val=++(*value);
  857.                       else
  858.                         expr->val.val=--(*value);
  859.                       expr->unary=un->next;
  860.                       FREE(un);
  861.                     }
  862.                   } else
  863.                     expr->val.val=*value;
  864.                 }
  865.                 if(pident->flags&FPL_VARIABLE_LESS32) {
  866.                   if(pident->flags&FPL_CHAR_VARIABLE) {
  867.                     expr->val.val=(long)((signed char)expr->val.val);
  868.                     *value=(long)((signed char)*value);
  869.                   } else {
  870.                     /* sixteen bits */
  871.                     expr->val.val=(long)((signed short)expr->val.val);
  872.                     *value=(long)((signed short)*value);
  873.                   }
  874.                 }
  875.               }
  876.               CALL(NewMember(scr, &expr));
  877.             }
  878.           }   /* end of integer handling */
  879.         } else if(ret && (*scr->text!=CHAR_OPEN_PAREN))
  880.           return(ret); /* FPLERR_IDENTIFIER_NOT_FOUND */
  881.         else {                     /* some sort of function */
  882.           /*
  883.            * FUNCTION HANDLER PART:
  884.            */
  885.  
  886.           struct fplArgument *pass; /* struct pointer to send as argument to
  887.                                        the function handler */
  888.           long allocspace;
  889.  
  890.           if(ret) {
  891.             if(!(scr->flags&FPLDATA_ALLFUNCTIONS) ||
  892.                *scr->text!=CHAR_OPEN_PAREN)
  893.               /* If the ability to parse all functions isn't turned on, or if
  894.                  the following character is not an open parenthesis, fail! */
  895.               return(ret);
  896.           }
  897.  
  898.           num=0;    /* number of arguments */
  899.  
  900.           expr->flags|=FPL_OPERAND|FPL_ACTION; /* This sure is action...! */
  901.  
  902.           GETMEM(pass, sizeof(struct fplArgument));
  903.  
  904.           if(!ident) {
  905.             /* The function does not exist as a declared function! */
  906.             STRDUP(pass->name, scr->buf);
  907.             pass->ID=FPL_UNKNOWN_FUNCTION;
  908.             text="o>"; /* optional parameter list as argument! */
  909.           } else {
  910.             pass->name=ident->name;
  911.             pass->ID=ident->data.external.ID;
  912.             text=ident->data.inside.format;
  913.           }
  914.           pass->argc=0;
  915.           pass->key=(void *)scr;
  916.  
  917.           if(!ident || FPL_OPTEXPRARG == ident->data.inside.ret) {
  918.             /*
  919.              * The function we invoked was not found regularly!
  920.          * Set return type!
  921.          */
  922.  
  923.         /*
  924.              * We try to determine whether it should return an int or a string.
  925.              * We interpret the return value as we should do to make it pass
  926.              * as a valid expression. That is, if the flag tells us this
  927.              * should be a string expression to be valid, we take it as a
  928.              * string, but if it tells us its an integer expression, we read
  929.              * it as an integer!!!
  930.              */
  931.  
  932.             if(control&CON_STRING)
  933.               hit = FPL_STRARG;
  934.             else {
  935.               if(control&CON_NUM)
  936.                 hit = FPL_INTARG;
  937.               else
  938.                 /*
  939.                  * We don't know which kind of return code the function
  940.                  * should give us!
  941.                  */
  942.                 hit = FPL_OPTEXPRARG;
  943.             }
  944.  
  945.       } else {
  946.             hit = UPPER(ident->data.inside.ret);
  947.             if(control&CON_STRING && (hit!=FPL_STRARG))
  948.               return FPLERR_UNEXPECTED_INT_STATEMENT;
  949.             if(control&CON_NUM && (hit!=FPL_INTARG))
  950.               return FPLERR_UNEXPECTED_STRING_STATEMENT;
  951.           }
  952.  
  953.           pass->ret = hit;
  954.  
  955.           if(*scr->text!=CHAR_OPEN_PAREN) {
  956.             CALL(Warn(scr, FPLERR_MISSING_PARENTHESES));  /* >warning< */
  957.           } else
  958.             scr->text++;
  959.  
  960.           CALL(Eat(scr));
  961.  
  962.           if(text && *text) {
  963.             uchar b='a';
  964.             uchar a;
  965.  
  966.             /* if the function takes arguments */
  967.  
  968.             /*
  969.              * Allocate arrays to use for data storage while parsing
  970.              * the arguments. Maximum number of arguments is
  971.              * MAX_ARGUMENTS.
  972.              */
  973.  
  974.             num=strlen(text);   /* number of arguments to this function */
  975.  
  976.             if(text[num-1]!=FPL_ARGLIST)
  977.               allocspace=num+1;
  978.             else
  979.               allocspace=MAX_ARGUMENTS;
  980.  
  981.             /*
  982.              * By adjusting the number of allocated bytes to the smallest
  983.              * necessary, my recursive example program used only a fifth
  984.              * as much memory as when always allocating memory for
  985.              * MAX_ARGUMENTS.
  986.              */
  987.  
  988.             /* allocate an array */
  989.             GETMEM(pass->argv, sizeof(uchar *)*allocspace);
  990.  
  991.             /* allocate new format string */
  992.             GETMEM(pass->format, sizeof(uchar)*allocspace);
  993.  
  994.             /* allocate allocate-flag string */
  995.             GETMEM(array, sizeof(uchar)*allocspace);
  996.  
  997.             while(!ret && *scr->text!=CHAR_CLOSE_PAREN && text && *text) {
  998.               b=(*text==FPL_ARGLIST)?b:UPPER(*text);
  999.           if(FPL_OPTARG == b &&
  1000.          CHAR_AND == scr->text[0])
  1001.                 a = FPL_OPTVARARG;
  1002.           else
  1003.                 a = b;
  1004.  
  1005.               if(pass->argc==allocspace) {
  1006.                 uchar *temp;
  1007.                 GETMEM(temp, sizeof(uchar *)*(allocspace+MAX_ARGUMENTS));
  1008.                 memcpy(temp, pass->argv, sizeof(uchar *)*allocspace);
  1009.                 FREE(pass->argv);
  1010.                 pass->argv=(void **)temp;
  1011.  
  1012.                 GETMEM(temp, sizeof(uchar)*(allocspace+MAX_ARGUMENTS));
  1013.                 memcpy(temp, pass->format, sizeof(uchar)*allocspace);
  1014.                 FREE(pass->format);
  1015.                 pass->format=temp;
  1016.  
  1017.                 GETMEM(temp, sizeof(uchar)*(allocspace+MAX_ARGUMENTS));
  1018.                 memcpy(temp, array, sizeof(uchar)*allocspace);
  1019.                 FREE(array);
  1020.                 array=temp;
  1021.                 
  1022.                 allocspace += MAX_ARGUMENTS;
  1023.               }
  1024.  
  1025.               switch(a) {
  1026.           case FPL_OPTEXPRARG:
  1027.               case FPL_OPTARG:
  1028.               case FPL_STRARG:
  1029.                 CALL(Expression(val, scr, (a==FPL_STRARG?CON_STRING:0), NULL));
  1030.  
  1031.                 if(a==FPL_STRARG || val->flags&FPL_STRING) {
  1032.           CALL(StringExpr(val, scr)); /* get more strings? */
  1033.  
  1034.                   /* Enter string symbol in the created format string! */
  1035.                   pass->format[pass->argc]=FPL_STRARG;
  1036.  
  1037.                   if(val->val.str) {
  1038.                     /* Set this to TRUE if deallocation is wanted on this
  1039.                        string after the function call! */
  1040.                     array[pass->argc]=!(val->flags&FPL_NOFREE);
  1041.                     /*
  1042.                      * Point to the string (that is zero terminated)!
  1043.                      */
  1044.                     pass->argv[pass->argc]=val->val.str->string;
  1045.                   } else {
  1046.                     GETMEM(string, sizeof(struct fplStr));
  1047.             memset(string, 0, sizeof(struct fplStr));
  1048.             pass->argv[pass->argc]=string->string;
  1049.                     array[pass->argc]=1; /* allocation has been done! */
  1050.                   }
  1051.                 } else {
  1052.                   pass->format[pass->argc]=FPL_INTARG;
  1053.                   pass->argv[pass->argc]=(void *)val->val.val;
  1054.                 }
  1055.                 pass->argc++;
  1056.                 break;
  1057.               case FPL_INTARG:
  1058.                 CALL(Expression(val, scr, CON_NUM, NULL));
  1059.                 pass->format[pass->argc]=FPL_INTARG;
  1060.                 pass->argv[pass->argc++]=(void *)val->val.val;
  1061.                 break;
  1062.           case FPL_OPTVARARG:
  1063.               case FPL_STRVARARG:
  1064.               case FPL_INTVARARG:
  1065.           case FPL_INTARRAYVARARG:
  1066.           case FPL_STRARRAYVARARG:
  1067.                 {
  1068.                   register ReturnCode ok;
  1069.                   if(*scr->text != CHAR_AND) {
  1070.                       ok = FPLERR_ILLEGAL_REFERENCE;
  1071.                   }
  1072.                   else {
  1073.                       scr->text++;
  1074.                       ok = FPL_OK;
  1075.                   }
  1076.                   CALL(Getword(scr));
  1077.                   /* Use the `pident' pointer here, cause the `ident' pointer
  1078.                      is already being used by the function we're about to
  1079.                      invoke! */
  1080.                   CALL(GetIdentifier(scr, scr->buf, &pident));
  1081.  
  1082.                   if(ok) {
  1083.                       /* missing &-character! */
  1084.                       if(pident->flags&FPL_REFERENCE)
  1085.                         /* get the referenced variable instead! */
  1086.                         pident = pident->data.variable.ref;
  1087.                       else
  1088.                       return FPLERR_ILLEGAL_REFERENCE; /* no reference! */
  1089.                   }
  1090.                 }
  1091.  
  1092.         if(FPL_INTARRAYVARARG == a || FPL_STRARRAYVARARG == a) {
  1093.             if(!pident->data.variable.num)
  1094.             return FPLERR_ILLEGAL_REFERENCE;
  1095.         }
  1096.         else if(FPL_OPTVARARG != a && pident->data.variable.num)
  1097.             /* only straight variables! */
  1098.             return FPLERR_ILLEGAL_PARAMETER;
  1099.  
  1100.                 if( (pident->flags&FPL_INT_VARIABLE &&
  1101.              (a==FPL_STRVARARG || a == FPL_STRARRAYVARARG)) ||
  1102.            (pident->flags&FPL_STRING_VARIABLE &&
  1103.             (a==FPL_INTVARARG || a == FPL_INTARRAYVARARG))) {
  1104.             CALL(Warn(scr, FPLERR_ILLEGAL_VARIABLE));
  1105.             /* can't copy wrong variable! */
  1106.             pass->argv[pass->argc]=NULL;
  1107.                 } else
  1108.             pass->argv[pass->argc]=(void *)pident;
  1109.  
  1110.                 pass->format[pass->argc++]=
  1111.           (pident->flags&FPL_STRING?
  1112.          (pident->data.variable.num?FPL_STRARRAYVARARG:FPL_STRVARARG):
  1113.            (pident->data.variable.num?FPL_INTARRAYVARARG:
  1114.             FPL_INTVARARG));
  1115.                 Eat(scr);
  1116.                 break;
  1117.               default:
  1118.                 CALL(Warn(scr, FPLERR_ILLEGAL_PARAMETER));
  1119.                 break; /* just ignore it and be happy! */
  1120.               }
  1121.               if(*text!=FPL_ARGLIST)
  1122.                 text++;
  1123.               if(*scr->text==CHAR_COMMA) {
  1124.                 scr->text++;
  1125.         CALL(Eat(scr)); /* eat white space! */
  1126.  
  1127.               }
  1128.             }
  1129.             pass->format[pass->argc]=CHAR_ASCII_ZERO;
  1130.             if(text && *text && !(*text&CASE_BIT)) {
  1131.               return FPLERR_MISSING_ARGUMENT;
  1132.               /*
  1133.                * This is a serious mis-use. The function is called with to few
  1134.                * parameters. At least one parameter missing is a required one.
  1135.                * I really can't figure out a way to survive such a shock!
  1136.                */
  1137.             }
  1138.           } else
  1139.             pass->format=NULL;
  1140.           if(*scr->text!=CHAR_CLOSE_PAREN) {
  1141.             CALL(Warn(scr, FPLERR_TOO_MANY_PARAMETERS)); /* too many parameters! */
  1142.             /* It's ok to continue without the parenthesis! */
  1143.           } else
  1144.             scr->text++;
  1145.  
  1146.           /*
  1147.            * Call the function!
  1148.            */
  1149.  
  1150.           CALL(CallFunction(scr, pass, ident));
  1151.  
  1152. #if 0
  1153.       fprintf(stderr, "**Return\n");
  1154. #endif
  1155.           CALL(GetMessage(scr, FPLMSG_RETURN, &msg));
  1156.           if(FPL_OPTEXPRARG == hit) {
  1157.             if(msg) {
  1158.               if(msg->flags&FPLMSG_FLG_INT) {
  1159.                 /* There is a return 'int' message! This may well be a
  1160.                    function returning int! */
  1161.                 hit = FPL_INTARG;
  1162.               }
  1163.               else {
  1164.                 /* found string, it returned a 'string' !!! */
  1165.                 hit = FPL_STRARG;
  1166.               }
  1167.             }
  1168.             /* There is no return nor hint! */
  1169.           }
  1170.  
  1171.           switch(hit) {
  1172.             case FPL_STRARG:
  1173. #if 0
  1174.           fprintf(stderr, "**String from %s\n", pass->name);
  1175.           fprintf(stderr, "**Flags %d %d\n", msg->flags&FPLMSG_FLG_BITS,
  1176.               FPLMSG_FLG_STRING);
  1177. #endif
  1178.               if(msg && ((msg->flags&FPLMSG_FLG_BITS) != FPLMSG_FLG_STRING))
  1179.                 return FPLERR_UNEXPECTED_INT_STATEMENT;
  1180.               if(!msg || !msg->message[0])
  1181.                 /* We got a zero length string or no string at all! */
  1182.                 expr->val.str=NULL; /* no string! */
  1183.               else
  1184.                 /* the copied string! */
  1185.                 expr->val.str=(struct fplStr *)msg->message[0];
  1186.             
  1187. #ifdef DEBUGMAIL
  1188.               DebugMail(scr, MAIL_RETURN_STRING, (long)pass->name,
  1189.                         expr->val.str);
  1190. #endif
  1191.               expr->flags=FPL_STRING|FPL_ACTION;
  1192.               break;
  1193.             case FPL_INTARG:
  1194.             default:
  1195. #if 0
  1196.           fprintf(stderr, "**Int from %s\n", pass->name);
  1197. #endif
  1198.               if(msg && ((msg->flags&FPLMSG_FLG_BITS) != FPLMSG_FLG_INT))
  1199.                 return FPLERR_UNEXPECTED_STRING_STATEMENT;
  1200.               /* only if integer! or the function is non-existent */
  1201.               expr->val.val=(msg?(long)msg->message[0]:0);
  1202. #ifdef DEBUGMAIL
  1203.               DebugMail(scr, MAIL_RETURN_INTEGER, (long)pass->name,
  1204.                         (void *)expr->val.val);
  1205. #endif
  1206.               CALL(NewMember(scr, &expr));
  1207.               break;
  1208.           }
  1209.           if(msg)
  1210.             DeleteMessage(scr, msg);
  1211.  
  1212.           if(!ident) {
  1213.             /*
  1214.              * The function we invoked was not found regularly!
  1215.          * Free the name we allocated temporarily.
  1216.          */
  1217.             FREE(pass->name); /* the name was strdup()'ed! */
  1218.       }
  1219.  
  1220.           while(pass->argc--) {
  1221.             if(pass->format[pass->argc]==FPL_STRARG && array[pass->argc]) {
  1222.               /* free the string if it's been marked to be freed!! */
  1223.               FREE((uchar *)pass->argv[pass->argc]-
  1224.                    offsetof(struct fplStr, string));
  1225.             }
  1226.           }
  1227.           if(pass->format) {
  1228.             FREE(pass->argv);
  1229.             FREE(pass->format);
  1230.             FREE(array);
  1231.           }
  1232.           FREE(pass);
  1233.         }
  1234.       } else {
  1235.  
  1236.           pos=0;
  1237.           switch(*scr->text) {
  1238.       case CHAR_MULTIPLY:
  1239.         /*
  1240.          * This is the 'contents of' operator!
  1241.          * The contents of the variable that follows this sign should
  1242.          * get the following rvalue.
  1243.          * Of course, we must first check that this really is a
  1244.          * 'pointer' to a variable.
  1245.          * If we declare this, make sure that it doesn't point to
  1246.          * anything at all!
  1247.          */
  1248.  
  1249.         while(*++scr->text==CHAR_MULTIPLY); /* just in case! */
  1250.  
  1251.         CALL(Getword(scr));
  1252.         if(control&CON_DECLARE) {
  1253.           return FPLERR_SYNTAX_ERROR; /* not yet supported */
  1254.         }
  1255.         else {
  1256.               CALL(GetIdentifier(scr, scr->buf, &ident));
  1257.           if(!(ident->flags&FPL_REFERENCE))
  1258.             return FPLERR_ILLEGAL_REFERENCE; /* referenced a non-reference! */
  1259.           if(!ident->data.variable.ref)
  1260.         return FPLERR_ILLEGAL_REFERENCE; /* illegal reference! */
  1261.  
  1262.           ident = ident->data.variable.ref; /* use the "actual" variable! */
  1263.  
  1264.           /* we have an identifier and the level is OK! */
  1265.           control |= CON_IDENT|CON_LEVELOK;
  1266.           continue; /* now we have the pointer for the *real* variable! */
  1267.         }
  1268.         break;
  1269.           case CHAR_ZERO:
  1270.             /*
  1271.              * Numbers starting with a '0' can be hex/oct/bin.
  1272.              */
  1273.             if(control&CON_STRING) {
  1274.               /* NO integers allowed! */
  1275.               return FPLERR_UNEXPECTED_INT_STATEMENT;
  1276.             }
  1277.             switch(scr->text[1]) {
  1278.             case CHAR_X:
  1279.             case CHAR_UPPER_X:
  1280.               /* hexadecimal number parser */
  1281.               for(scr->text+=2; isxdigit(*scr->text); scr->text++)
  1282.                 expr->val.val=expr->val.val*16+ (isdigit(*scr->text)?
  1283.                                          *scr->text-CHAR_ZERO:
  1284.                                          UPPER(*scr->text)-CHAR_UPPER_A+10);
  1285.               break;
  1286.             case CHAR_B:
  1287.             case CHAR_UPPER_B:
  1288.               /* binary number parser */
  1289.               for(scr->text+=2;*scr->text==CHAR_ZERO || *scr->text==CHAR_ONE;)
  1290.                 expr->val.val=expr->val.val*2+ *scr->text++ - CHAR_ZERO;
  1291.               break;
  1292.             case CHAR_ZERO:
  1293.             case CHAR_ONE:
  1294.             case CHAR_TWO:
  1295.             case CHAR_THREE:
  1296.             case CHAR_FOUR:
  1297.             case CHAR_FIVE:
  1298.             case CHAR_SIX:
  1299.             case CHAR_SEVEN:
  1300.               /* octal number parser */
  1301.               for(scr->text++; isodigit(*scr->text);)
  1302.                 expr->val.val=expr->val.val*8+ *scr->text++ - CHAR_ZERO;
  1303.               break;
  1304.             default:
  1305.               /* a single zero is simply 0 */
  1306.               scr->text++;
  1307.               expr->val.val=0;
  1308.               break;
  1309.             }
  1310.             CALL(NewMember(scr, &expr));
  1311.             break;
  1312.         /* end of case CHAR_ZERO: */
  1313.  
  1314.           case CHAR_ONE:
  1315.           case CHAR_TWO:
  1316.           case CHAR_THREE:
  1317.           case CHAR_FOUR:
  1318.           case CHAR_FIVE:
  1319.           case CHAR_SIX:
  1320.           case CHAR_SEVEN:
  1321.           case CHAR_EIGHT:
  1322.           case CHAR_NINE:
  1323.             /*
  1324.              * We hit a number between 1 and 9.
  1325.              */
  1326.             if(control&CON_STRING) {
  1327.               /* NO integers allowed! */
  1328.               CALL(Warn(scr, FPLERR_UNEXPECTED_INT_STATEMENT));
  1329.             }
  1330.             do
  1331.               expr->val.val= expr->val.val*10 + *scr->text++ - CHAR_ZERO;
  1332.             while(isdigit(*scr->text));
  1333.             CALL(NewMember(scr, &expr));
  1334.         break;
  1335.  
  1336.         case CHAR_QUOTATION_MARK:
  1337.             if(control&CON_NUM) {
  1338.               /* NO integers allowed! */
  1339.               CALL(Warn(scr, FPLERR_UNEXPECTED_STRING_STATEMENT));
  1340.             }
  1341.             CALL(Convert(val, scr));
  1342.             /* This returned a string! */
  1343.             expr->val.str=val->val.str;
  1344.             expr->flags=FPL_STRING;
  1345.         CALL(StringExpr(expr, scr));
  1346.         break;
  1347.  
  1348.         case CHAR_APOSTROPHE:
  1349.             /*
  1350.              * Apostrophes surround character. Returns ASCII code.
  1351.              */
  1352.             if(control&CON_STRING) {
  1353.               /* NO integers allowed! */
  1354.               CALL(Warn(scr, FPLERR_UNEXPECTED_INT_STATEMENT));
  1355.             }
  1356.             CALL(ReturnChar((scr->text++, scr), &expr->val.val, FALSE));
  1357.             if(*scr->text!=CHAR_APOSTROPHE) {
  1358.               CALL(Warn(scr, FPLERR_MISSING_APOSTROPHE)); /* >warning< */
  1359.               /* just continue as nothing has ever happened! */
  1360.             } else
  1361.               scr->text++;
  1362.             CALL(NewMember(scr, &expr));
  1363.         break;
  1364.  
  1365.         case CHAR_OPEN_PAREN:
  1366.             CALL(Expression(val, (++scr->text, scr), CON_GROUNDLVL|CON_NUM, NULL));
  1367.             if(*scr->text!=CHAR_CLOSE_PAREN) {
  1368.               CALL(Warn(scr, FPLERR_MISSING_PARENTHESES)); /* >warning< */
  1369.               /* Go on anyway! */
  1370.             } else
  1371.               scr->text++;
  1372.             expr->val.val=val->val.val;
  1373.             CALL(NewMember(scr, &expr));
  1374.             break;
  1375.  
  1376.         case CHAR_NOT_OPERATOR:
  1377.             CALL(AddUnary(scr, expr, OP_NOT));
  1378.             ++scr->text;
  1379.             break;
  1380.  
  1381.         case CHAR_ONCE_COMPLEMENT:
  1382.             CALL(AddUnary(scr, expr, OP_COMPL));
  1383.             ++scr->text;
  1384.           break;
  1385.  
  1386.         case CHAR_PLUS:
  1387.             if(scr->text[1]==CHAR_PLUS) {
  1388.               expr->flags|=FPL_ACTION;
  1389.               scr->text+=2;
  1390.               CALL(AddUnary(scr, expr, OP_PREINC));
  1391.             } else {
  1392.               CALL(AddUnary(scr, expr, OP_PLUS));
  1393.               scr->text++;
  1394.             }
  1395.             break;
  1396.  
  1397.         case CHAR_MINUS:
  1398.             if(scr->text[1]==CHAR_MINUS) {
  1399.               expr->flags|=FPL_ACTION;
  1400.               scr->text+=2;
  1401.               CALL(AddUnary(scr, expr, OP_PREDEC));
  1402.             } else {
  1403.               CALL(AddUnary(scr, expr, OP_MINUS));
  1404.               scr->text++;
  1405.             }
  1406.             break;
  1407.  
  1408.           default:
  1409.  
  1410.             if((*scr->text==CHAR_SEMICOLON && control&CON_SEMICOLON) ||
  1411.                (*scr->text==CHAR_CLOSE_PAREN && control&CON_PAREN)
  1412.                && basexpr==expr && expr->operator==OP_NOTHING) {
  1413.               /* for(;;) support.
  1414.                  There must not have been a previous operand or operator */
  1415.               pos=expr->val.val=TRUE;
  1416.             } else {   /* no operand results in error! */
  1417.               CALL(Warn(scr, FPLERR_MISSING_OPERAND)); /* WARNING! */
  1418.               expr->operator=OP_NOTHING; /* reset */
  1419.             }
  1420.           break;
  1421.       }
  1422.           if(pos)
  1423.           break;
  1424.       }
  1425.  
  1426.     } else {                                         /* waiting for operator */
  1427.       uchar *point=scr->text;
  1428.  
  1429.       switch(*scr->text) {
  1430.       case CHAR_ASSIGN:
  1431.         if(scr->text[1]==CHAR_ASSIGN) {
  1432.           expr->operator=OP_EQUAL;
  1433.           scr->text+=2;
  1434.         }
  1435.         break;
  1436.       case CHAR_AND:
  1437.     if(scr->text[1]==CHAR_AND) {
  1438.           /*
  1439.            * This is a logical AND (&&)
  1440.            */
  1441.           scr->text+=2;
  1442.  
  1443.           /*
  1444.            * Get result from everything to the left of this!
  1445.            */
  1446.           CALL(Calc(scr, val, basexpr));
  1447.  
  1448.           /*
  1449.            * Clean the expression so far.
  1450.            */
  1451.           Clean(scr, basexpr);    /* erase the list */
  1452.  
  1453.           /*
  1454.            * Start a new list with this result
  1455.            */
  1456.           GETMEM(expr, sizeof(struct Expr));
  1457.           memset(expr, 0, sizeof(struct Expr));
  1458.           basexpr=expr;
  1459.           expr->val.val = val->val.val;
  1460.  
  1461.           if(!expr->val.val) {
  1462.             /*
  1463.              * In this case, its like in the 'a && b' expression and 'a'
  1464.              * equals 0. Then we should skip the 'b' expression.
  1465.              */
  1466.             CALL(ScanForNext(scr, OP_LOGAND));
  1467.             expr->flags = FPL_OPERAND;
  1468.           }
  1469.           continue;
  1470.  
  1471.         } else {
  1472.           expr->operator=OP_BINAND;
  1473.           scr->text++;
  1474.         }
  1475.         break;
  1476.       case CHAR_OR:
  1477.         if(scr->text[1]==CHAR_OR) {
  1478.           /*
  1479.            * This is a logical OR operator (||)
  1480.            */
  1481.           scr->text+=2;
  1482.  
  1483.           /*
  1484.            * Get result from everything to the left of this!
  1485.            */
  1486.           CALL(Calc(scr, val, basexpr));
  1487.  
  1488.           /*
  1489.            * Clean the expression so far.
  1490.            */
  1491.           Clean(scr, basexpr);    /* erase the list */
  1492.  
  1493.           /*
  1494.            * Start a new list with this result
  1495.            */
  1496.           GETMEM(expr, sizeof(struct Expr));
  1497.           memset(expr, 0, sizeof(struct Expr));
  1498.           basexpr=expr;
  1499.           expr->val.val = val->val.val;
  1500.  
  1501.           if(expr->val.val) {
  1502.             /*
  1503.              * In this case, its like in the 'a || b' expression and 'a'
  1504.              * equals 1. Then we should skip the 'b' expression.
  1505.              */
  1506.             CALL(ScanForNext(scr, OP_LOGOR));
  1507.             expr->flags = FPL_OPERAND;
  1508.           }
  1509.           continue;
  1510.  
  1511.         } else {
  1512.           expr->operator=OP_BINOR;
  1513.           scr->text++;
  1514.         }
  1515.         break;
  1516.       case CHAR_PLUS:
  1517.         expr->operator=OP_PLUS;
  1518.         ++scr->text;
  1519.         break;
  1520.       case CHAR_MINUS:
  1521.         expr->operator=OP_MINUS;
  1522.         ++scr->text;
  1523.         break;
  1524.       case CHAR_QUESTION:
  1525.         ++scr->text;
  1526.         /*
  1527.          * This is the first operator in a conditional operator sequence (?)
  1528.          */
  1529.  
  1530.         /*
  1531.          * Get result from everything to the left of this!
  1532.          */
  1533.         CALL(Calc(scr, val, basexpr));
  1534.  
  1535.         /*
  1536.          * Clean the expression so far.
  1537.          */
  1538.         Clean(scr, basexpr);    /* erase the list */
  1539.  
  1540.         /*
  1541.          * Start a new list with this result
  1542.          */
  1543.         GETMEM(expr, sizeof(struct Expr));
  1544.         memset(expr, 0, sizeof(struct Expr));
  1545.         expr->flags = FPL_OPERAND;
  1546.         basexpr=expr;
  1547.  
  1548.         if(val->val.val) {
  1549.           /*
  1550.            * In this case, its like in the 'a ? b : c' expression and 'a'
  1551.            * equals 1. Then we should skip the 'c' expression.
  1552.            */
  1553.           CALL(Expression(val, scr, CON_NORMAL, NULL));
  1554.           if(*scr->text++!=CHAR_COLON)
  1555.             return FPLERR_ILLEGAL_CONDOP;
  1556.           CALL(ScanForNext(scr, OP_COND2));          
  1557.         }
  1558.         else {
  1559.           /*
  1560.            * In this case, its like in the 'a ? b : c' expression and 'a'
  1561.            * equals 0. Then we should skip the 'b' expression.
  1562.            */
  1563.           CALL(ScanForNext(scr, OP_COND1));
  1564.           if(*scr->text++!=CHAR_COLON)
  1565.             return FPLERR_ILLEGAL_CONDOP;
  1566.           CALL(Expression(val, scr, CON_NORMAL, NULL));
  1567.         }
  1568.         expr->val.val = val->val.val;
  1569.         continue; /* check for next operator */
  1570.  
  1571.         break;
  1572. #if 0
  1573.       case CHAR_COLON:
  1574.         if(conditional) {
  1575.           /* only if preceeded with the regular '?' operator! */
  1576.       conditional--;
  1577.           expr->operator=OP_COND2;
  1578.           ++scr->text;
  1579.         }
  1580.         break;
  1581. #endif
  1582.       case CHAR_MULTIPLY:
  1583.         expr->operator=OP_MULTIPLY;
  1584.         ++scr->text;
  1585.         break;
  1586.       case CHAR_DIVIDE:
  1587.         expr->operator=OP_DIVISION;
  1588.         ++scr->text;
  1589.         break;
  1590.       case CHAR_REMAIN:
  1591.         expr->operator=OP_REMAIN;
  1592.         ++scr->text;
  1593.         break;
  1594.       case CHAR_XOR:
  1595.         expr->operator=OP_BINXOR;
  1596.         ++scr->text;
  1597.         break;
  1598.       case CHAR_LESS_THAN:
  1599.         if(scr->text[1]==CHAR_ASSIGN) {
  1600.           scr->text+=2;
  1601.           expr->operator=OP_LESSEQ;
  1602.         } else if(scr->text[1]==CHAR_LESS_THAN) {
  1603.           scr->text+=2;
  1604.           expr->operator=OP_SHIFTL;
  1605.         } else {
  1606.           scr->text++;
  1607.           expr->operator=OP_LESS;
  1608.         }
  1609.         break;
  1610.       case CHAR_GREATER_THAN:
  1611.     if(scr->text[1]==CHAR_ASSIGN) {
  1612.           expr->operator= OP_GRETEQ;
  1613.           scr->text+=2;
  1614.         } else if(scr->text[1]==CHAR_GREATER_THAN) {
  1615.           scr->text+=2;
  1616.           expr->operator=OP_SHIFTR;
  1617.         } else {
  1618.           scr->text++;
  1619.           expr->operator=OP_GRET;
  1620.         }
  1621.         break;
  1622.       case CHAR_NOT_OPERATOR:
  1623.         if(scr->text[1]==CHAR_ASSIGN) {
  1624.           expr->operator=OP_NOTEQ;
  1625.           scr->text+=2;
  1626.         }
  1627.         break;
  1628.       case CHAR_COMMA:
  1629.         if(control&CON_GROUNDLVL) {
  1630.           /*
  1631.            * Get result from everything to the left of this!
  1632.            * For unary operators.
  1633.            */
  1634.           CALL(Calc(scr, val, basexpr));
  1635.  
  1636.           Clean(scr, basexpr);
  1637.           GETMEM(basexpr, sizeof(struct Expr));
  1638.           expr=basexpr;
  1639.           expr->val.val=0;
  1640.           expr->unary=NULL;
  1641.           expr->operator=expr->flags=OP_NOTHING;
  1642.           expr->next=NULL;
  1643.           scr->text++;
  1644.         }
  1645.         break;
  1646.       }
  1647.       if(point==scr->text)
  1648.         break;
  1649.       expr->flags&=~FPL_OPERAND; /* clear the operand bit */
  1650.     }
  1651.   } while(1);
  1652.  
  1653.   if(!(control&(CON_DECLARE /* |CON_ACTION */ ))) {
  1654.     /*
  1655.      * Get result of the current expression only if this isn't called
  1656.      * as a declaring (no one wants the return code from 'int a'!)
  1657.      * or a stand-alone (they have no receiver anyway) statement.
  1658.      */
  1659.     CALL(Calc(scr, val, basexpr));
  1660.  
  1661.     /*
  1662.      * If this was a stand alone statement, including no action returns an
  1663.      * error!
  1664.      */
  1665.     if(control&CON_ACTION && !(val->flags&FPL_ACTION)) {
  1666.       CALL(Warn(scr, FPLERR_NO_ACTION));
  1667.       /* but we can just as good keep on anyway! */
  1668.     }
  1669.   }
  1670.  
  1671.   Clean(scr, basexpr);    /* erase the rest of the list */
  1672.   if(dims)
  1673.     FREE(dims);
  1674.   return(FPL_OK);
  1675. }
  1676.  
  1677. /**********************************************************************
  1678.  *
  1679.  * ReturnCode Calc();
  1680.  *
  1681.  * Returns the result in the first Expr struct of the expression that
  1682.  * the second parameter holds. This function does not free the expression
  1683.  * list.
  1684.  *
  1685.  *******/
  1686.  
  1687. ReturnCode REGARGS
  1688. Calc(struct Data *scr,
  1689.      struct Expr *val,
  1690.      struct Expr *basexpr)
  1691. {
  1692.   /* lower value=higher priority. Order as the operator list in script.h:
  1693.    *|    +  -  /  * << >>  %  &  |  ^ && ||  ~    ?   :  == <= >=  <  > != ! */
  1694.   const static uchar priority[]={
  1695.     255, 1, 1, 0, 0, 2, 2, 0, 5, 7, 6, 8, 9, 255, 10, 10, 4, 3, 3, 3, 3, 4, 255
  1696.     };
  1697.  
  1698.   ReturnCode ret;
  1699.   uchar pri, minpri=255, maxpri=0;
  1700.   struct Expr *expr=basexpr, *last;
  1701.   struct Unary *un, *next;
  1702.  
  1703.   /* first all Unary expressions */
  1704.   if(!(expr->flags&FPL_STRING)) {
  1705.     while(expr) {
  1706.       if(priority[expr->operator]<minpri)
  1707.         minpri=priority[expr->operator]; /* get the lowest priority */
  1708.       if(priority[expr->operator]>maxpri && expr->operator!=OP_NOTHING)
  1709.         maxpri=priority[expr->operator]; /* get the highest priority */
  1710.       if(expr->flags&FPL_STRING) {
  1711.         CALL(Warn(scr, FPLERR_ILLEGAL_VARIABLE));
  1712.         /*
  1713.          * A string among the integers!
  1714.          * We remove this and try next!
  1715.          */
  1716.  
  1717.         last=expr->next;
  1718.         FREE(expr); /* delete this bastard from the expression!!! */
  1719.         expr=last;
  1720.       } else {
  1721.         un=expr->unary;
  1722.         while(un) {
  1723.           switch(un->unary) {
  1724.           case OP_NOT:
  1725.             expr->val.val=!expr->val.val;
  1726.             break;
  1727.           case OP_COMPL:
  1728.             expr->val.val=~expr->val.val;
  1729.             break;
  1730.           case OP_MINUS:
  1731.             expr->val.val=-expr->val.val;
  1732.             break;
  1733.             /*simply ignored!
  1734.               case OP_PLUS:
  1735.               break;
  1736.               */
  1737.           case OP_PREDEC:
  1738.           case OP_PREINC:
  1739.             CALL(Warn(scr, FPLERR_ILLEGAL_PREOPERATION));
  1740.             /* just ignore it! */
  1741.           }
  1742.           next=un->next;
  1743.           FREE(un);
  1744.           un=next;
  1745.         }
  1746.       }
  1747.       expr=expr->next;
  1748.     }
  1749.   }
  1750.   /*
  1751.    * Calculate all members of the linked list in the proper way and put
  1752.    * the result in "val->val.val" before returning "ret". Check for operators
  1753.    * with priority within `minpri' and `maxpri' which we got in the loop
  1754.    * above.
  1755.    *
  1756.    * Check priority level by priority level and perform the right actions.
  1757.    * When reaching the maxpri, there is only one number left: the result!
  1758.    */
  1759.  
  1760.   for(pri=minpri; pri<=maxpri; pri++) {
  1761.     last=expr=basexpr;
  1762.     while(expr=expr->next) {
  1763.       if(priority[expr->operator]==pri) {
  1764.         last->flags|=expr->flags;
  1765.         switch(expr->operator) {
  1766.         case OP_MULTIPLY:
  1767.           last->val.val*=expr->val.val;
  1768.           break;
  1769.         case OP_DIVISION:
  1770.           if(!expr->val.val) {
  1771.             CALL(Warn(scr, FPLERR_DIVISION_BY_ZERO));
  1772.             /* we give a zero as result! */
  1773.             last->val.val=0;
  1774.           } else
  1775.             last->val.val/=expr->val.val;
  1776.           break;
  1777.         case OP_REMAIN:
  1778.           if(!expr->val.val) {
  1779.             CALL(Warn(scr, FPLERR_DIVISION_BY_ZERO));
  1780.             last->val.val=0;
  1781.           } else
  1782.             last->val.val%=expr->val.val;
  1783.           break;
  1784.         case OP_SHIFTL:
  1785.           last->val.val<<=expr->val.val;
  1786.           break;
  1787.         case OP_SHIFTR:
  1788.           last->val.val>>=expr->val.val;
  1789.           break;
  1790.         case OP_BINAND:
  1791.           last->val.val&=expr->val.val;
  1792.           break;
  1793.         case OP_BINOR:
  1794.           last->val.val|=expr->val.val;
  1795.           break;
  1796.         case OP_BINXOR:
  1797.           last->val.val^=expr->val.val;
  1798.           break;
  1799.         case OP_PLUS:
  1800.           last->val.val+=expr->val.val;
  1801.           break;
  1802.         case OP_MINUS:
  1803.           last->val.val-=expr->val.val;
  1804.           break;
  1805.         case OP_EQUAL:
  1806.           last->val.val=last->val.val==expr->val.val;
  1807.           break;
  1808.         case OP_NOTEQ:
  1809.           last->val.val=last->val.val!=expr->val.val;
  1810.           break;
  1811.         case OP_LESSEQ:
  1812.           last->val.val=last->val.val<=expr->val.val;
  1813.           break;
  1814.         case OP_LESS:
  1815.           last->val.val=last->val.val<expr->val.val;
  1816.           break;
  1817.         case OP_GRETEQ:
  1818.           last->val.val=last->val.val>=expr->val.val;
  1819.           break;
  1820.         case OP_GRET:
  1821.           last->val.val=last->val.val>expr->val.val;
  1822.           break;
  1823.         case OP_LOGOR:
  1824.           last->val.val=last->val.val||expr->val.val;
  1825.           break;
  1826.         case OP_LOGAND:
  1827.           last->val.val=last->val.val&&expr->val.val;
  1828.           break;
  1829.         case OP_COND1:
  1830.           if(expr->next && expr->next->operator==OP_COND2) {
  1831.             last->val.val=last->val.val?expr->val.val:expr->next->val.val;
  1832.           } else {
  1833.             CALL(Warn(scr, FPLERR_ILLEGAL_CONDOP)); /* WARNING! */
  1834.             last->val.val=expr->val.val; /* get the number we have! */
  1835.           }
  1836.           break;
  1837.         }
  1838.         last->next=expr->next;
  1839.         FREE(expr);
  1840.         expr=last;
  1841.       } else
  1842.         last=expr;
  1843.     }
  1844.   }
  1845.   val->val.val=basexpr->val.val; /* get the final value */
  1846.   val->flags=basexpr->flags; /* copy the flags */
  1847.   return(FPL_OK);
  1848. }
  1849.  
  1850. /**********************************************************************
  1851.  *
  1852.  * AddUnary();
  1853.  *
  1854.  * Build a linked list on the unary member of the Expr struct!
  1855.  *
  1856.  ******/
  1857.  
  1858. ReturnCode REGARGS
  1859. AddUnary(struct Data *scr,
  1860.          struct Expr *expr,
  1861.          Operator unary)
  1862. {
  1863.   struct Unary *next=expr->unary;
  1864.  
  1865.   GETMEM(expr->unary, sizeof(struct Unary));
  1866.   expr->unary->unary=unary;
  1867.   expr->unary->next=next;
  1868.  
  1869.   return(FPL_OK);
  1870. }
  1871.  
  1872.  
  1873. /**********************************************************************
  1874.  *
  1875.  * Clean()
  1876.  *
  1877.  * Erases every track of the linked TalStruct list...
  1878.  *
  1879.  ******/
  1880.  
  1881. void REGARGS Clean(struct Data *scr, struct Expr *basexpr)
  1882. {
  1883.   struct Expr *last;
  1884.   while(basexpr) {
  1885.     last=basexpr->next;
  1886.     FREE(basexpr);
  1887.     basexpr=last;
  1888.   }
  1889. }
  1890.  
  1891. /**********************************************************************
  1892.  *
  1893.  * Convert()
  1894.  *
  1895.  * Converts the following "string" in the line to a string which it returns.
  1896.  *
  1897.  *********/
  1898.  
  1899. static ReturnCode INLINE Convert(struct Expr *expr, struct Data *scr)
  1900. {
  1901.   ReturnCode ret=FPL_OK;
  1902.   long a;
  1903.   unsigned long pos=0;  /* start position */
  1904.  
  1905.   struct fplStr *pointer, *pek;
  1906.  
  1907.   expr->flags|=FPL_STRING;
  1908.  
  1909.   GETMEM(pointer, sizeof(struct fplStr) + ADDSTRING_DEFAULT);
  1910.   /* create default string space */
  1911.  
  1912.   pointer->alloc=ADDSTRING_DEFAULT;
  1913.   pointer->len=0;
  1914.  
  1915.   expr->val.str=pointer;
  1916.  
  1917. #ifdef DEBUG
  1918.   CheckMem(scr, pointer);
  1919. #endif
  1920.   do {
  1921.     scr->text++;
  1922.     while(*scr->text!=CHAR_QUOTATION_MARK) {
  1923.       CALL(ReturnChar(scr, &a, TRUE));
  1924.       if(a<256) {
  1925.         pointer->string[pos]=a;
  1926.         if(++pos>=pointer->alloc) {
  1927.           GETMEM(pek, (pointer->alloc+=ADDSTRING_INC)+sizeof(struct fplStr));
  1928.           memcpy(pek, pointer, pos+sizeof(struct fplStr));
  1929.           FREE(pointer);
  1930.           pointer=pek;
  1931.           expr->val.str=pointer;
  1932.         }
  1933.       }
  1934.     }
  1935.     scr->text++;
  1936.     CALL(Eat(scr));
  1937.   } while(*scr->text==CHAR_QUOTATION_MARK);
  1938.   pointer->string[pos]=0; /* zero terminate */
  1939.   pointer->len=pos;       /* length of string */
  1940.   expr->val.str=pointer;
  1941.  
  1942.   return(ret);
  1943. }
  1944.  
  1945. /**********************************************************************
  1946.  *
  1947.  * GetArrayInfo()
  1948.  *
  1949.  * Read the []'s and store the information. Make sure you're standing on
  1950.  * the open bracket!
  1951.  *
  1952.  * Set the int num points to, to any number if you want to limit the number
  1953.  * of dimension reads.
  1954.  */
  1955.  
  1956. static ReturnCode INLINE GetArrayInfo(struct Data *scr,
  1957.                                       long *dims,  /* long array */
  1958.                                       long *num,   /* number of dims */
  1959.                                       long control,
  1960.                                       uchar *name)  /* variable name */
  1961. {
  1962.   struct Expr *val;
  1963.   ReturnCode ret=FPL_OK;
  1964.   long maxnum=*num;
  1965.   GETMEM(val, sizeof(struct Expr));
  1966.   *num=0;
  1967.   if(*scr->text==CHAR_OPEN_BRACKET) {
  1968.     do {
  1969.       scr->text++; /* pass the open bracket */
  1970.       /* eval the expression: */
  1971.       CALL(Expression(val, scr, CON_GROUNDLVL|CON_NUM, NULL));
  1972.  
  1973.       if(*scr->text!=CHAR_CLOSE_BRACKET) {
  1974.         /* no close bracket means error */
  1975.         CALL(Warn(scr, FPLERR_MISSING_BRACKET)); /* >warning< */
  1976.         /* go on anyway! */
  1977.       } else
  1978.         scr->text++;
  1979.  
  1980.       if(val->val.val<(control&CON_DECLARE?1:0)) {
  1981.         /* illegal result of the expression */
  1982.         /*
  1983.          * Write back the original variable name to the buffer!
  1984.          */
  1985.         strcpy(scr->buf, name);
  1986.         ret = FPLERR_ILLEGAL_ARRAY;
  1987.         break;
  1988.       }
  1989.  
  1990.       dims[(*num)++]=val->val.val; /* Add another dimension */
  1991.       if(*num==maxnum) {
  1992.         /* we've hit the roof! */
  1993.         break;
  1994.       } else if(*num==MAX_DIMS) {
  1995.         /* if we try to use too many dimensions... */
  1996.         ret=FPLERR_ILLEGAL_ARRAY;
  1997.         /*
  1998.          * Write back the original variable name to the buffer!
  1999.          */
  2000.         strcpy(scr->buf, name);
  2001.         break;
  2002.       }
  2003.       /*
  2004.        * Go on as long there are braces and we are declaring OR
  2005.        * as long the `num' variable tells us (you, know: when
  2006.        * you want to read character five in a member of a
  2007.        * three dimensional string array, it could look like
  2008.        * "int a=string[2][3][4][5];" ... :-)
  2009.        */
  2010.     } while(*scr->text==CHAR_OPEN_BRACKET);
  2011.   }
  2012.   FREE(val);
  2013.   return(ret);
  2014. }
  2015.  
  2016. /**********************************************************************
  2017.  *
  2018.  * ArrayNum()
  2019.  *
  2020.  * Return which array position we should look in when the user wants the
  2021.  * array member presented as a number of dimensions and an array with the
  2022.  * dimension sizes.
  2023.  *
  2024.  ******/
  2025.  
  2026. long REGARGS
  2027. ArrayNum(long num,     /* number of dimensions specified */
  2028.          long dnum,    /* number of dimensions declared  */
  2029.          long *dims,   /* dimensions specified */
  2030.          long *decl)   /* declared dimension information */
  2031. {
  2032.   long i;
  2033.   long pos=0;
  2034.   long base=1;
  2035.   if(num!=dnum)
  2036.     /*
  2037.      * Then we can't get proper information!!!
  2038.      */
  2039.     return(-1);
  2040.   for(i=0; i<num; i++) {
  2041.     if(dims[i]>=decl[i])
  2042.       return(-1);
  2043.  
  2044.     pos+=dims[i]*base;
  2045.     base*=decl[i];
  2046.   }
  2047.   return(pos);
  2048. }
  2049.  
  2050.  
  2051. /**********************************************************
  2052.  *
  2053.  * CallFunction()
  2054.  *
  2055.  * Calls a function. Internal, external or inside!!
  2056.  *
  2057.  *******/
  2058.  
  2059. ReturnCode REGARGS
  2060. CallFunction(struct Data *scr,
  2061.              struct fplArgument *pass,
  2062.              struct Identifier *ident)
  2063. {
  2064.   ReturnCode ret;
  2065.   if(ident && ident->flags&FPL_INTERNAL_FUNCTION) {
  2066.     CALL(functions(pass));
  2067.   } else if(ident && ident->flags&FPL_INSIDE_FUNCTION) {
  2068.     CALL(inside(scr, pass, ident));
  2069.   } else { /* if (EXTERNAL_FUNCTION) */
  2070.     pass->funcdata=ident?ident->data.external.data:(void *)NULL;
  2071.  
  2072. #if defined(AMIGA) && defined(SHARED)
  2073.     if(ret=CheckStack(scr, scr->stack_limit, scr->stack_margin)) {
  2074.       if(ret==1)
  2075.         return(FPLERR_OUT_OF_MEMORY);
  2076.       else
  2077.         return(FPLERR_OUT_OF_STACK);
  2078.     }
  2079. #endif
  2080.  
  2081.     if(ident && ident->data.external.func) {
  2082.       /*
  2083.        * If this is non-zero, a function specific function pointer
  2084.        * has been assigned to it! In that case we should call that
  2085.        * function instead of the traditional, global one!
  2086.        */
  2087.       CALL(InterfaceCall(scr, pass, ident->data.external.func));
  2088.     } else {
  2089.       CALL(InterfaceCall(scr, pass, scr->function));
  2090.     }
  2091.  
  2092.   }
  2093.   return(FPL_OK);
  2094. }
  2095.  
  2096. /**********************************************************************
  2097.  *
  2098.  * inside();
  2099.  *
  2100.  * This function takes care of the inside function callings within a
  2101.  * FPL program (or in a FPL program where the function was declared using
  2102.  * `export').
  2103.  *
  2104.  ******/
  2105.  
  2106. static ReturnCode INLINE inside(struct Data *scr,
  2107.                                 struct fplArgument *arg,
  2108.                                 struct Identifier *func)
  2109. {
  2110.   /*
  2111.    * The function has been declared as an `inside' one.
  2112.    */
  2113.  
  2114.   ReturnCode ret=FPL_OK;
  2115.   struct Identifier *pident; /* pointer to identifier */
  2116.   struct Identifier *ident;
  2117.   uchar *t=scr->text;
  2118.   struct Local *locals=NULL;
  2119.   long p=scr->prg;
  2120.   long vp=scr->virprg;
  2121.   uchar *vf=scr->virfile;
  2122.   uchar count; /* parameter counter */
  2123.   uchar *text;
  2124.   struct Condition con;
  2125.   struct Expr *val;
  2126.   struct fplStr *string;
  2127.   uchar oldret;
  2128.   uchar cont;
  2129.   long search;
  2130.   struct Program *prog=scr->prog;
  2131.   struct fplVariable *tempvar;
  2132.   uchar reference;
  2133.   long breaks;
  2134.  
  2135.   GETMEM(val, sizeof(struct Expr));
  2136.   if(scr->prog->name != func->data.inside.file) {
  2137.     struct Program *prog=scr->programs;
  2138.     while(prog) {
  2139.       if(prog->name && !strcmp(prog->name, func->data.inside.file))
  2140.         break;
  2141.       prog=prog->next;
  2142.     }
  2143.     if(prog) {
  2144.       CALL(LeaveProgram(scr, scr->prog));
  2145.       CALL(GetProgram(scr, prog));
  2146.       scr->prog=prog;
  2147.     } else
  2148.       return FPLERR_INTERNAL_ERROR; /* This is a dead-end error! */
  2149.   }
  2150.  
  2151.   if(func->flags&FPL_INSIDE_NOTFOUND) {
  2152.     /*
  2153.      * We have no current information about where this function
  2154.      * is to be found. Search for it and store the location in
  2155.      * ->text and ->prg.
  2156.      */
  2157.  
  2158.     cont=TRUE;
  2159.     search=(func->data.inside.ret==FPL_STRARG)?CMD_STRING:
  2160.     (func->data.inside.ret==FPL_INTARG)?CMD_INT:CMD_VOID;
  2161.  
  2162.     /*
  2163.      * Start searching from the declaration position to enable local functions!
  2164.      */
  2165.  
  2166.     scr->text=(&scr->prog->program)[scr->prog->startprg-1]+
  2167.       func->data.inside.col;
  2168.     scr->prg=func->data.inside.prg;
  2169.     scr->virprg=func->data.inside.virprg;
  2170.     scr->virfile=func->data.inside.virfile;
  2171.     while(cont && !ret) {
  2172.       switch(*scr->text) {
  2173.       case CHAR_OPEN_BRACE:
  2174.         /* ...go to the corresponding brace */
  2175.         ret=GetEnd(scr, CHAR_CLOSE_BRACE, CHAR_OPEN_BRACE, TRUE);
  2176.         break;
  2177.       case CHAR_OPEN_PAREN:
  2178.         /* ...go to the corresponding parenthesis */
  2179.         ret=GetEnd(scr, CHAR_CLOSE_PAREN, CHAR_OPEN_PAREN, TRUE);
  2180.         break;
  2181.       case CHAR_QUOTATION_MARK:
  2182.         scr->text++;
  2183.         /* dirty use of function: */
  2184.         ret=GetEnd(scr, CHAR_QUOTATION_MARK, CHAR_QUOTATION_MARK, FALSE);
  2185.         break;
  2186.       case CHAR_ASCII_ZERO:
  2187.         if(Newline(scr))
  2188.           ret=FPLERR_INSIDE_NOT_FOUND;
  2189.         break;
  2190.       case CHAR_DIVIDE: /* to eat comments */
  2191.       case CHAR_SPACE:
  2192.       case CHAR_TAB:
  2193.       case CHAR_NEWLINE:
  2194.         if(Eat(scr))
  2195.           ret=FPLERR_INSIDE_NOT_FOUND;
  2196.         if(*scr->text==CHAR_HASH) {
  2197.           /* This should read a #line statement for new virtual line number */
  2198.           while(*scr->text++!=CHAR_NEWLINE);
  2199.           scr->virprg++;
  2200.         }
  2201.         break;
  2202.       case CHAR_CLOSE_BRACE: /* local function searches might hit this! */
  2203.         ret=FPLERR_INSIDE_NOT_FOUND;
  2204.         break;
  2205.       default:
  2206.         if(isident(*scr->text)) {
  2207.           Getword(scr);
  2208.           GetIdentifier(scr, scr->buf, &pident);
  2209.           if(pident && /* valid identifier */
  2210.              pident->data.external.ID==search) {  /* and it's the right one */
  2211.             if(!Getword(scr)) {
  2212.               GetIdentifier(scr, scr->buf, &pident);
  2213.               if(pident && pident->flags&FPL_INSIDE_FUNCTION) /* an inside */
  2214.                 cont=strcmp(pident->name, func->name); /* is it the right? */
  2215.             }
  2216.           } else
  2217.             while(isident(*scr->text))
  2218.               scr->text++;
  2219.         } else
  2220.           scr->text++;
  2221.         break;
  2222.       }
  2223.     }
  2224.     if(ret) {
  2225.       strcpy(scr->buf, func->name); /* enable better error report! */
  2226.       scr->prg=p;
  2227.       scr->text=t;
  2228.       scr->virprg=vp;
  2229.       return FPLERR_INSIDE_NOT_FOUND; /* dead end error */
  2230.     }
  2231.     func->data.inside.col=scr->text-(&scr->prog->program)[scr->prg-1];
  2232.     func->data.inside.prg=scr->prg;
  2233.     func->data.inside.virprg=scr->virprg;
  2234.     func->data.inside.virfile=scr->virfile;
  2235.     func->flags&=~FPL_INSIDE_NOTFOUND; /* we have found it! */
  2236.   } else {
  2237.     /*
  2238.      * We know where to find this function!
  2239.      */
  2240.  
  2241.     scr->prg=func->data.inside.prg;
  2242.     scr->text=(&scr->prog->program)[scr->prg-1]+func->data.inside.col;
  2243.     scr->virprg=func->data.inside.virprg;
  2244.     scr->virfile=func->data.inside.virfile;
  2245.   }
  2246.  
  2247.   /*
  2248.    * Some of this boring stuff only has to be done on interepreted function
  2249.    * calls, since compiled ones have much smarted function argument
  2250.    * handling!
  2251.    */
  2252.   if(!(func->flags & FPL_COMPILER_ADDED)) {
  2253.     
  2254.     /**********************************
  2255.      * PARSE THE PARAMETER LIST HERE! *
  2256.      **********************************/
  2257.   
  2258.     CALL(Eat(scr));
  2259.   
  2260.     if(*scr->text!=CHAR_OPEN_PAREN) {
  2261.       CALL(Warn(scr, FPLERR_MISSING_PARENTHESES));
  2262.       /* we can survive without that! */
  2263.     } else
  2264.       scr->text++;
  2265.   
  2266.     if(func->data.inside.format) {
  2267.       /*
  2268.        * We won't hit this if no arguments is prototyped.
  2269.        */
  2270.   
  2271.       count=0; /* parameter counter */
  2272.       text=func->data.inside.format;
  2273.   
  2274.       if(!*text) {
  2275.         if(!Getword(scr) && strcmp(scr->buf, "void")) {
  2276.           /* it should be "void" or nothing! If it wasn't we fail! */
  2277.           CALL(Warn(scr, FPLERR_ILLEGAL_DECLARE));
  2278.         }
  2279.       } else {
  2280.         while(*text && !ret) {
  2281.           CALL(Getword(scr));
  2282.           CALL(GetIdentifier(scr, scr->buf, &ident));
  2283.       CALL(Eat(scr));
  2284.           if(scr->text[0]==CHAR_MULTIPLY) {
  2285.         reference=TRUE;
  2286.         scr->text++; /* pass it! */
  2287.       }
  2288.       else
  2289.             reference=FALSE; /* no reference! */
  2290.   
  2291.           switch(*text) {
  2292.           case FPL_STRARG:
  2293.           case FPL_INTARG:
  2294.         if(reference) {
  2295.           /*
  2296.            * It was said to a symbol reference!!
  2297.            */
  2298.               return FPLERR_ILLEGAL_REFERENCE;
  2299.         }
  2300.   
  2301.             if((*text==FPL_STRARG &&
  2302.                ident->data.external.ID!=CMD_STRING) ||
  2303.                (*text==FPL_INTARG &&
  2304.                ident->data.external.ID!=CMD_INT))
  2305.               return FPLERR_ILLEGAL_DECLARE;
  2306.   
  2307.             /*
  2308.              * Declare the following word as a string or integer
  2309.              * variable.
  2310.              */
  2311.             GETMEM(pident, sizeof(struct Identifier));
  2312.   
  2313.             CALL(Getword(scr));
  2314.   
  2315.             tempvar=&pident->data.variable;
  2316.   
  2317.             pident->flags=(*text==FPL_INTARG?FPL_INT_VARIABLE:
  2318.                            FPL_STRING_VARIABLE)|
  2319.                              (ident->flags&FPL_VARIABLE_LESS32);
  2320.   
  2321.             STRDUP(pident->name, scr->buf);
  2322.   
  2323.             tempvar->num=0; /* This is not an array */
  2324.             tempvar->size=1; /* This is not an array */
  2325.             GETMEM(tempvar->var.val32, sizeof(void *));
  2326.             if(*text==FPL_INTARG) {
  2327.               tempvar->var.val32[0]=(long)arg->argv[count];
  2328.             } else {
  2329.               /* Store string length in variable `len' */
  2330.               register long len=GETSTRLEN(arg->argv[count]);
  2331.               GETMEM(tempvar->var.str[0], sizeof(struct fplStr)+len);
  2332.               tempvar->var.str[0]->alloc=len;
  2333.   
  2334.               /* We copy the ending zero termination too! */
  2335.               memcpy(tempvar->var.str[0]->string, ((uchar *)arg->argv[count]), len+1);
  2336.               tempvar->var.str[0]->len=len;
  2337.             }
  2338.             /*
  2339.              * Emulate next level variable declaration by adding one
  2340.              * to the ->level member here... dirty but (fully?)
  2341.              * functional!!!! ;-)
  2342.              */
  2343.   
  2344.             pident->level=scr->varlevel+1;
  2345.             pident->file=scr->prog->name;
  2346.             pident->func=func;
  2347.             CALL(AddVar(scr, pident, &locals));
  2348.             break;
  2349.           case FPL_STRVARARG:
  2350.           case FPL_INTVARARG:
  2351.       case FPL_STRARRAYVARARG:
  2352.       case FPL_INTARRAYVARARG:
  2353.         if(!reference) {
  2354.           /*
  2355.            * It was never said to be a symbol reference!!
  2356.            */
  2357.               return FPLERR_ILLEGAL_REFERENCE;
  2358.         }
  2359.             if((*text==FPL_STRVARARG || *text == FPL_STRARRAYVARARG) &&
  2360.            ident->data.external.ID!=CMD_STRING) {
  2361.           return FPLERR_ILLEGAL_DECLARE;
  2362.   
  2363.             } else if((*text==FPL_INTVARARG || *text == FPL_INTARRAYVARARG) &&
  2364.               ident->data.external.ID!=CMD_INT) {
  2365.               return FPLERR_ILLEGAL_DECLARE;
  2366.             }
  2367.             /*
  2368.              * Declare the following word as a variable which
  2369.              * will use the struct fplVariable pointer as given in the
  2370.              * calling parameter list.
  2371.              */
  2372.   
  2373.             CALL(Getword(scr));
  2374.   
  2375.         if(*text == FPL_INTARRAYVARARG ||
  2376.            *text == FPL_STRARRAYVARARG) {
  2377.             CALL(Eat(scr));
  2378.                 if(CHAR_OPEN_BRACKET != scr->text[0])
  2379.                   return FPLERR_ILLEGAL_DECLARE;
  2380.             if(GetEnd(scr, CHAR_CLOSE_BRACKET, CHAR_OPEN_BRACKET, FALSE))
  2381.                   return FPLERR_MISSING_BRACKET;
  2382.         }
  2383.   
  2384.             if(arg->argv[count]) {
  2385.               /*
  2386.                * If the wrong kind of variable was sent in the function call, no
  2387.                * varible will be sent, and no one will be declared.
  2388.                */
  2389.   
  2390.               GETMEM(pident, sizeof(struct Identifier));
  2391.   
  2392.               *pident=*(struct Identifier *)arg->argv[count];
  2393.               pident->flags |= FPL_REFERENCE;
  2394.               pident->data.variable.ref= (struct Identifier *)arg->argv[count];
  2395.               /* original fplVariable position */
  2396.   
  2397.               STRDUP(pident->name, scr->buf);
  2398.   
  2399.               pident->level=scr->varlevel+1;
  2400.               pident->file=scr->prog->name;
  2401.               pident->func=func;
  2402.               CALL(AddVar(scr, pident, &locals));
  2403.             }
  2404.             break;
  2405.           }
  2406.           CALL(Eat(scr));
  2407.   
  2408.           if(*++text && *scr->text++!=CHAR_COMMA)
  2409.             /*
  2410.              * There is no way out from this error exception. Leaving a parameter
  2411.              * really is a sever thing!
  2412.              */
  2413.             return(FPLERR_MISSING_ARGUMENT);
  2414.           count++;
  2415.         }
  2416.       }
  2417.   
  2418.       CALL(Eat(scr));
  2419.   
  2420.       if(*scr->text!=CHAR_CLOSE_PAREN) {
  2421.         CALL(Warn(scr, FPLERR_MISSING_PARENTHESES));
  2422.         /* who needs ending parentheses? */
  2423.       } else
  2424.         scr->text++;
  2425.     } else {
  2426.       /*
  2427.        * No argument is useable to this function. There might be a
  2428.        * `void' keyword here, but nothing else! Just search for the
  2429.        * closing parenthesis to fasten interpreting!
  2430.        */
  2431.   
  2432.       if(ret=GetEnd(scr, CHAR_CLOSE_PAREN, CHAR_OPEN_PAREN, FALSE)) {
  2433.         CALL(Warn(scr, FPLERR_MISSING_PARENTHESES));
  2434.         /* ok, then search for the open brace where the program starts! */
  2435.         ret=GetEnd(scr, CHAR_OPEN_BRACE, CHAR_OPEN_PAREN, FALSE);
  2436.         if(ret) {
  2437.           CALL(Warn(scr, FPLERR_MISSING_BRACE));
  2438.         } else
  2439.           scr->text--; /* back on brace */
  2440.         /* ok, then we say that the program starts right here! */
  2441.       }
  2442.     }
  2443.   
  2444.     CALL(Eat(scr));
  2445.     if(*scr->text!=CHAR_OPEN_BRACE) {
  2446.       CALL(Warn(scr, FPLERR_MISSING_BRACE));
  2447.       /* we can do with a start without it! */
  2448.     } else
  2449.       scr->text++;
  2450.  
  2451.   } /* end of non-compiled function specific setups */
  2452.   
  2453.   oldret=scr->strret;
  2454.   scr->strret=func->data.inside.ret==FPL_STRARG; /* should we receive a string? */
  2455.  
  2456.   con.bracetext=scr->text;
  2457.   con.braceprg=scr->prg;
  2458.   text=(void *)scr->func; /* backup current */
  2459.   scr->func=func;
  2460.  
  2461.   breaks = scr->breaks;
  2462.   scr->breaks=0;
  2463.  
  2464.   {
  2465.     register struct fplArgument *targ=arg;
  2466.     scr->arg = arg; /* for compiled functions to use */
  2467.     arg = targ; /* store the old */
  2468.   }
  2469.  
  2470.   /*********************
  2471.    * RUN THE FUNCTION! *
  2472.    *********************/
  2473.  
  2474.   scr->prog->openings++;
  2475.   ret=Script(scr, val, SCR_BRACE|SCR_FUNCTION, &con);
  2476.   scr->prog->openings--;
  2477.  
  2478.   scr->breaks=breaks;
  2479.  
  2480.   if(!(func->flags&FPL_COMPILER_ADDED)) {
  2481.     /*
  2482.      * Delete all variables created on our list for use
  2483.      * only in the function we just came back from!
  2484.      */
  2485.     DelLocalVar(scr, &locals);
  2486.   }
  2487.  
  2488.   scr->arg = arg; /* get back previous */
  2489.  
  2490.   if(!ret && val->flags & FPL_CONTINUE)
  2491.     ret = FPLERR_ILLEGAL_CONTINUE;
  2492.  
  2493.   if(ret) {
  2494.     if(scr->prog != prog) {
  2495.       LeaveProgram(scr, scr->prog); /* leave the failed program! */
  2496.       GetProgram(scr, prog); /* fetch the previous program again! */
  2497.     }
  2498.     return(ret);
  2499.   }
  2500.   scr->func=(void *)text; /* restore last */
  2501.  
  2502.   FREE(val);
  2503.  
  2504.   scr->text=t;
  2505.   scr->prg=p;
  2506.   scr->virprg=vp;
  2507.   scr->virfile=vf;
  2508.   scr->strret=oldret;
  2509.   if(scr->prog!=prog) {
  2510.     CALL(LeaveProgram(scr, scr->prog));
  2511.     scr->prog=prog;
  2512.     CALL(GetProgram(scr, scr->prog));
  2513.   }
  2514.   return(FPL_OK);
  2515. }
  2516.  
  2517. static ReturnCode INLINE PrototypeInside(struct Data *scr,
  2518.                      struct Expr *val,
  2519.                      long control,
  2520.                      struct Identifier *ident)
  2521. {
  2522.   /*
  2523.    * Prototyping an `inside' function!
  2524.    *
  2525.    * We have already received the return type, now we must
  2526.    * parse the paraters given within the parentheses. Legal
  2527.    * parameters are only combinations of `string', `int',
  2528.    * `string &' and `int &', or a single `void' (if no argument
  2529.    * should be sent to the function). Arguments specified in
  2530.    * a prototype is required, there is no way to specify an
  2531.    * optional parameter or a parameter list.
  2532.    */
  2533.  
  2534.   struct Identifier *pident;
  2535.   long pos=0;
  2536.   ReturnCode ret = FPL_OK;
  2537.   uchar *array;
  2538.   uchar found=ident?TRUE:FALSE;
  2539.  
  2540.   if(!found) {
  2541.     GETMEM(pident, sizeof(struct Identifier));
  2542.     STRDUP(pident->name, scr->buf);
  2543.   } else {
  2544.     /* we already know about this function! */
  2545.     if(ident->flags&(FPL_INTERNAL_FUNCTION|FPL_KEYWORD|FPL_EXTERNAL_FUNCTION))
  2546.       return FPLERR_IDENTIFIER_USED;
  2547.     pident = ident;
  2548.   }
  2549.  
  2550.   if(!found || (found && ident->flags&FPL_INSIDE_NOTFOUND)) {
  2551.     /* we know where this is... */
  2552.     pident->data.inside.col=scr->text-(&scr->prog->program)[scr->prg-1];
  2553.     pident->data.inside.prg=scr->prg;
  2554.     pident->data.inside.file=scr->prog->name;
  2555.     pident->data.inside.virprg=scr->virprg;
  2556.     pident->data.inside.virfile=scr->virfile;
  2557.  
  2558.     pident->file=scr->prog->name; /* file! */
  2559.     pident->func=scr->func; /* declared in this function */
  2560.     pident->level=control&CON_DECLGLOB?0:scr->varlevel;
  2561.   }
  2562.  
  2563.   if(found) {
  2564.     /* we already know about this function! */
  2565.  
  2566.     CALL(GetEnd(scr, CHAR_CLOSE_PAREN, CHAR_OPEN_PAREN, TRUE));
  2567.  
  2568.     CALL(Eat(scr));
  2569.  
  2570.     if(scr->text[0]==CHAR_OPEN_BRACE) {
  2571.       /* now the function is found! */
  2572.       if(!(ident->flags&FPL_INSIDE_NOTFOUND))
  2573.         /* the function has already been defined and is defined here again! */
  2574.         return FPLERR_IDENTIFIER_USED;
  2575.  
  2576.       ident->flags&=~FPL_INSIDE_NOTFOUND;
  2577.  
  2578.       if(GetEnd(scr, CHAR_CLOSE_BRACE, CHAR_OPEN_BRACE, TRUE))
  2579.         return FPLERR_MISSING_BRACE;
  2580.       scr->text--; /* back on close brace */
  2581.       val->flags|=FPL_DEFUNCTION;
  2582.     }
  2583.  
  2584.     return FPL_OK;
  2585.   }
  2586.  
  2587.   pident->flags=FPL_INSIDE_FUNCTION|
  2588.     (control&CON_DECLEXP?FPL_EXPORT_SYMBOL:0)|
  2589.       (control&CON_DECLGLOB?FPL_GLOBAL_SYMBOL:0);
  2590.  
  2591.   scr->text++; /* pass the open parenthesis */
  2592.  
  2593.   CALL(Eat(scr));
  2594.  
  2595.   GETMEM(array, MAX_ARGUMENTS * sizeof(uchar));
  2596.  
  2597.   while(pos<MAX_ARGUMENTS) {
  2598.     if(*scr->text==CHAR_CLOSE_PAREN) {
  2599.       scr->text++;
  2600.       break;
  2601.     }
  2602.     CALL(Getword(scr));
  2603.     CALL(GetIdentifier(scr, scr->buf, &ident));
  2604.     CALL(Eat(scr));
  2605.     switch(ident->data.external.ID) {
  2606.     case CMD_VOID:
  2607.       if(*scr->text!=CHAR_CLOSE_PAREN) {
  2608.         CALL(Warn(scr, FPLERR_ILLEGAL_PROTOTYPE));
  2609.         CALL(GetEnd(scr, CHAR_CLOSE_PAREN, CHAR_OPEN_PAREN, TRUE));
  2610.       } else
  2611.         scr->text++;
  2612.       break;
  2613.  
  2614.     case CMD_STRING:
  2615.     case CMD_INT:
  2616.       if(*scr->text==CHAR_MULTIPLY) {
  2617.         scr->text++;
  2618.         Getword(scr); /* eat word if there's any! */
  2619.         if(CHAR_OPEN_BRACKET == scr->text[0]) {
  2620.           if(GetEnd(scr, CHAR_CLOSE_BRACKET, CHAR_OPEN_BRACKET, FALSE))
  2621.             return FPLERR_MISSING_BRACKET;
  2622.           array[pos]=(ident->data.external.ID==CMD_STRING)?FPL_STRARRAYVARARG:
  2623.           FPL_INTARRAYVARARG;
  2624.         }
  2625.         else
  2626.           array[pos]=(ident->data.external.ID==CMD_STRING)?FPL_STRVARARG:
  2627.           FPL_INTVARARG;
  2628.       } else
  2629.         array[pos]=(ident->data.external.ID==CMD_STRING)?FPL_STRARG:
  2630.         FPL_INTARG;
  2631.       break;
  2632.  
  2633.     default:
  2634.       CALL(Warn(scr, FPLERR_ILLEGAL_PROTOTYPE));
  2635.       continue; /* if we against all odds are ordered to go on! */
  2636.     }
  2637.     if(CMD_VOID == ident->data.external.ID)
  2638.       break;
  2639.  
  2640.     pos++;
  2641.     if(isident(*scr->text)) {
  2642.       Getword(scr);
  2643.       CALL(Eat(scr));
  2644.     }
  2645.  
  2646.     if(*scr->text==CHAR_COMMA)
  2647.       scr->text++;
  2648.     else if(*scr->text!=CHAR_CLOSE_PAREN) {
  2649.       CALL(Warn(scr, FPLERR_ILLEGAL_PROTOTYPE));
  2650.       /* we can go on if we just forgot the closing parenthesis */
  2651.     }
  2652.   }
  2653.  
  2654.   array[pos]=0; /* terminate string */
  2655.  
  2656.   /*
  2657.    * We have all information now. AddIdentifier().
  2658.    */
  2659.  
  2660.   pident->data.inside.ret=(control&CON_DECLSTR)?FPL_STRARG:
  2661.     (control&CON_DECLINT)?FPL_INTARG:FPL_VOIDARG;
  2662.   GETMEM(pident->data.inside.format, pos+1);
  2663.   strcpy(pident->data.inside.format, array);
  2664.   FREE(array);
  2665.  
  2666.   CALL(Eat(scr)); /* Eat white space */
  2667.  
  2668.  
  2669.   if(*scr->text==CHAR_OPEN_BRACE) {
  2670.     /* It's the actual function!!! */
  2671.     if(GetEnd(scr, CHAR_CLOSE_BRACE, CHAR_OPEN_BRACE, TRUE))
  2672.       return FPLERR_MISSING_BRACE;
  2673.     scr->text--; /* back on close brace */
  2674.     val->flags|=FPL_DEFUNCTION;
  2675.   } else {
  2676.     val->flags&=~FPL_DEFUNCTION;
  2677.     pident->flags|=FPL_INSIDE_NOTFOUND;
  2678.   }
  2679.   CALL(AddVar(scr, pident,
  2680.               control&CON_DECLGLOB?&scr->globals:&scr->locals));
  2681.  
  2682.   return(ret);
  2683. }
  2684.